স্ক্রিপ্ট শুরুর পরে দোভাষী বেছে নিন যেমন হ্যাশবাংয়ের ভিতরে / অন্যথায়


16

কোনও স্ক্রিপ্ট সম্পাদনকারী দোভাষীকে গতিশীলভাবে বেছে নেওয়ার কোনও উপায় আছে কি? আমার কাছে একটি স্ক্রিপ্ট রয়েছে যা আমি দুটি পৃথক সিস্টেমে চলছি, এবং আমি যে দোভাষীটি ব্যবহার করতে চাইছি তা দুটি সিস্টেমে বিভিন্ন স্থানে অবস্থিত। আমি যা করতে পেরেছি তা হ্যাশব্যাং লাইনটি প্রতিবার আমি যখন স্যুইচ করলাম তখন তা পরিবর্তন করা। আমি এমন কিছু করতে চাই যা এর যৌক্তিক সমতুল্য (আমি বুঝতে পারি যে এই সঠিক নির্মাণটি অসম্ভব):

if running on system A:
    #!/path/to/python/on/systemA
elif running on system B:
    #!/path/on/systemB

#Rest of script goes here

বা আরও ভাল এটি হতে পারে, যাতে এটি প্রথম দোভাষী ব্যবহার করার চেষ্টা করে এবং এটি যদি এটির সন্ধান না করে তবে এটি দ্বিতীয়টি ব্যবহার করে:

try:
    #!/path/to/python/on/systemA
except: 
    #!path/on/systemB

#Rest of script goes here

স্পষ্টতই, আমি এর পরিবর্তে আমি যেখানে আছি /path/to/python/on/systemA myscript.py বা তার /path/on/systemB myscript.pyউপর নির্ভর করে এটি সম্পাদন করতে পারি, তবে আসলে আমার কাছে একটি মোড়ক স্ক্রিপ্ট রয়েছে যা চালু হয় myscript.py, তাই আমি হাতের পরিবর্তে পাইথন ইন্টারপ্রেটার প্রোগ্রামটি নির্দিষ্ট করে বলতে চাই।


3
শেবাং ছাড়াই দোভাষীকে ফাইল হিসাবে 'স্ক্রিপ্টের বাকী অংশ' পাস করা এবং ifশর্তটি ব্যবহার করা কি আপনার পক্ষে বিকল্প নয়? মত,if something; then /bin/sh restofscript.sh elif...
মেজগুলি

এটি একটি বিকল্প, আমি এটি বিবেচনাও করেছি, তবে আমার চেয়ে কিছুটা মেসেঞ্জার। যেহেতু হ্যাশবাং লাইনে যুক্তি অসম্ভব তাই আমি মনে করি সত্যই আমি সেই পথে যাব।
dkv

আমি এই প্রশ্নের উত্পন্ন বিভিন্ন উত্তর বিস্তৃত পছন্দ।
ওসকার স্কোগ

উত্তর:


27

না, এটি কাজ করবে না। দুটি অক্ষর #!একেবারে ফাইলের প্রথম দুটি অক্ষর হওয়া দরকার (তবে কীভাবে যদি বিবৃতিটি ব্যাখ্যা করা হয় তবে আপনি কীভাবে নির্দিষ্ট করবেন?)। এটি "ম্যাজিক নম্বর" গঠন করে যা exec()ফাংশনগুলির পরিবার সনাক্ত করে যখন তারা নির্ধারণ করতে পারে যে কোনও ফাইল কোনও স্ক্রিপ্ট (যার জন্য দোভাষী দরকার) বা বাইনারি ফাইল (যা নেই)।

শেবাং লাইনের ফর্ম্যাটটি বেশ কড়া। এটির জন্য একজন দোভাষীর কাছে একটি নিখুঁত পথ এবং এটিতে সর্বাধিক একটি যুক্তি থাকা দরকার।

আপনি যা করতে পারেন তা হ'ল env:

#!/usr/bin/env interpreter

এখন, পথে envহল সাধারণত /usr/bin/env যে কোন গ্যারান্টি, কিন্তু টেকনিক্যালি।

এই আপনি পরিবর্তন করতে পারবেন PATH, যাতে প্রতিটি সিস্টেমের উপর এনভায়রনমেন্ট ভেরিয়েবল interpreter(এটা হতে bash, pythonবা perl, বা যতটুকু আপনি আছে) পাওয়া যায়।

এই পদ্ধতির একটি খারাপ দিকটি হ'ল অনুবাদকের পক্ষে যুক্তিটি বহনযোগ্যভাবে পাস করা অসম্ভব হবে।

এই যে মানে

#!/usr/bin/env awk -f

এবং

#!/usr/bin/env sed -f

কিছু সিস্টেমে কাজ করার সম্ভাবনা কম।

আর একটি সুস্পষ্ট পদ্ধতি হ'ল জিএনইউ অটোটুলগুলি (বা কিছু সহজ টেম্প্লেটিং সিস্টেম) ব্যবহার করে দোভাষী খুঁজে পেতে এবং একটি ./configureধাপে ফাইলের মধ্যে সঠিক পাথ স্থাপন করা যা প্রতিটি সিস্টেমে স্ক্রিপ্ট ইনস্টল করার পরে চালিত হবে।

একজন স্পষ্টত দোভাষী দিয়ে স্ক্রিপ্টটি চালাও করতে পারেন, তবে আপনি এড়াতে চাইছেন:

$ sed -f script.sed

ঠিক আছে, আমি বুঝতে পারি যে #!শুরুতে আসা উচিত, যেহেতু এটি শেল নয় যা সেই লাইনটি প্রসেস করে। আমি ভাবছিলাম যে হ্যাশবাং লাইনের ভিতরে যুক্তি যুক্ত করার কোনও উপায় আছে যা যদি / অন্যথায় সমান হয়। আমি আমার সাথে ঘৃণা এড়ানোর আশা করছিলাম PATHতবে আমি অনুমান করি যে এটি আমার একমাত্র বিকল্প।
dkv

1
আপনি যখন ব্যবহার করেন #!/usr/bin/awk, আপনি ঠিক যেমন একটি যুক্তি সরবরাহ করতে পারেন #!/usr/bin/awk -f। বাইনারি তুমি ইশারা হয় তাহলে env, যুক্তি বাইনারি আপনাকে জিজ্ঞাসা করছি env, জন্য সন্ধান হিসেবে #!/usr/bin/env awk
ডোপঘোতি

2
@dkv এটা না এটি দুটি তর্কযুক্ত একটি দোভাষী ব্যবহার করে এবং এটি কিছু সিস্টেমে কাজ করতে পারে তবে অবশ্যই তা নয়।
কুসালানন্দ

3
লিনাক্সে @dkv /usr/bin/envএটি একক যুক্তি দিয়ে চলে awk -f
ইল্কাচ্চু

1
@ কুসালানন্দ, না, এটাই কথা ছিল। আপনি একটি স্ক্রিপ্ট নামক যদি foo.awkhashbang লাইন দিয়ে #!/usr/bin/env awk -fএবং একে ডাকতে ./foo.awkতারপর, লিনাক্স, কি envদুটি প্যারামিটার দেখতে পাবে না awk -fএবং ./foo.awk। এটি আসলে /usr/bin/awk -fস্থান সহ (ইত্যাদি) সন্ধান করে।
ইল্কাচ্চু

27

আসল প্রোগ্রামের জন্য সঠিক দোভাষী খুঁজে পেতে আপনি সর্বদা একটি মোড়ক স্ক্রিপ্ট তৈরি করতে পারেন:

#!/bin/bash
if something ; then
    interpreter=this
    script=/some/path/to/program.real
    flags=()
else
    interpreter=that
    script=/other/path/to/program.real
    flags=(-x -y)
fi
exec "$interpreter" "${flags[@]}" "$script" "$@"

ব্যবহারকারীর PATHমতো মোড়ক সংরক্ষণ করুন programএবং আসল প্রোগ্রামটি একপাশে বা অন্য নামে রাখুন।

অ্যারের #!/bin/bashকারণে আমি হ্যাশবাংয়ে ব্যবহার করেছি flags। আপনার যদি কোনও পরিবর্তনশীল সংখ্যা বা এই জাতীয় পতাকা সংরক্ষণের প্রয়োজন না হয় এবং এগুলি না করে করতে পারেন তবে স্ক্রিপ্টটির সাথে বহনযোগ্যভাবে কাজ করা উচিত #!/bin/sh


2
exec "$interpreter" "${flags[@]}" "$script" "$@"প্রক্রিয়া গাছ পরিষ্কার রাখার জন্যও আমি ব্যবহার করেছি । এটি প্রস্থান কোডটিও প্রচার করে।
ruuenza

@ আরউউঞ্জা, আহ হ্যাঁ, স্বাভাবিকভাবেই exec
ইল্কাচ্চু

1
#!/bin/shপরিবর্তে ভাল হবে না #!/bin/bash? এমনকি যদি /bin/shএকটি আলাদা শেলের একটি সিমিলিংক হয় তবে এটি বেশিরভাগ (সমস্ত না থাকলে) * নিক্স সিস্টেমে থাকা উচিত, এবং এটি স্ক্রিপ্ট লেখককে বাশিজমের পরিবর্তে পোর্টেবল স্ক্রিপ্ট তৈরি করতে বাধ্য করে।
সের্গেই কোলোডিয়াজনি

@ সার্জি কলোডিয়াজনি, হেই, আমি এর আগে উল্লেখ করার কথা ভেবেছিলাম, তবে তা হয়নি। এর জন্য ব্যবহৃত অ্যারেটি flagsএকটি মানহীন বৈশিষ্ট্য, তবে এটি পরিবর্তনশীল সংখ্যক পতাকা সংরক্ষণের জন্য যথেষ্ট দরকারী তাই আমি এটি রাখার সিদ্ধান্ত নিয়েছি।
ইল্কাচ্চু

বা ব্যবহার / বিন / SH এবং মাত্র প্রতিটি শাখায় সরাসরি অনুবাদক আহবান script=/what/ever; something && exec this "$script" "$@"; exec that "$script" -x -y "$@"। এক্সিকিউট ব্যর্থতা পরীক্ষা করতে আপনি ত্রুটি যুক্ত করতে পারেন could
jrw32982 মোনিকা

11

আপনি একটি বহুভক্ত (দুটি ভাষার সংমিশ্রণ )ও লিখতে পারেন। / বিন / শ বিদ্যমান থাকার গ্যারান্টিযুক্ত।

এটিতে কুৎসিত কোডের খারাপ দিক রয়েছে এবং সম্ভবত কিছু /bin/shগুলি বিভ্রান্ত হতে পারে। কিন্তু env/ ইউএসআর / বিন / এনভিভের বাইরে অন্য কোথাও উপস্থিত বা উপস্থিত না থাকলে এটি ব্যবহার করা যেতে পারে । আপনি কিছু সুন্দর অভিনব নির্বাচন করতে চাইলে এটি ব্যবহার করা যেতে পারে।

স্ক্রিপ্টের প্রথম অংশটি নির্ধারণ করে যে / বিন / শের সাহায্যে দোভাষী হিসাবে চলাকালীন কোন দোভাষী ব্যবহার করতে হবে, কিন্তু সঠিক দোভাষী দ্বারা চালিত হলে তা উপেক্ষা করা হবে। execশেলটি প্রথম অংশের চেয়ে বেশি চালানো থেকে রোধ করতে ব্যবহার করুন ।

পাইথনের উদাহরণ:

#!/bin/sh
'''
' 2>/dev/null
# Python thinks this is a string, docstring unfortunately.
# The shell has just tried running the <newline> program.
find_best_python ()
{
    for candidate in pypy3 pypy python3 python; do
        if [ -n "$(which $candidate)" ]; then
            echo $candidate
            return
        fi
    done
    echo "Can't find any Python" >/dev/stderr
    exit 1
}
interpreter="$(find_best_python)"   # Replace with something fancier.
# Run the rest of the script
exec "$interpreter" "$0" "$@"
'''

3
আমি মনে করি আমি এর মধ্যে একটি আগেও দেখেছি, তবে ধারণাটি এখনও সমানভাবে ভয়াবহ ... তবে, আপনি সম্ভবত exec "$interpreter" "$0" "$@"স্ক্রিপ্টটির নামও প্রকৃত দোভাষীর কাছে পেতে চান । (এবং তারপরে আশা করি সেটআপ করার সময় কেউ মিথ্যা $0
বলবে না

6
স্ক্যালার প্রকৃতপক্ষে এর সিনট্যাক্সে বহুবৃত্ত স্ক্রিপ্টগুলির জন্য সমর্থন রয়েছে: যদি স্কাল স্ক্রিপ্টটি শুরু হয় #!, স্কালা একটি মিলের সমস্ত কিছু উপেক্ষা করে !#; এটি আপনাকে সেখানে একটি স্বেচ্ছাসেবী ভাষায় নির্বিচারে জটিল স্ক্রিপ্ট কোড স্থাপন করতে দেয় এবং তারপরে execস্ক্রিপ্টের সাথে স্কালা এক্সিকিউশন ইঞ্জিন।
Jörg W Mittag


2

আমি কুসালানন্দের এবং ইল্কচাচের উত্তর পছন্দ করি, তবে এখানে একটি বিকল্প উত্তর যা প্রশ্নটি যা চেয়েছিল তা আরও সরাসরি করে, কারণ এটি জিজ্ঞাসা করা হয়েছিল।

#!/usr/bin/ruby -e exec "non-existing-interpreter", ARGV[0] rescue exec "python", ARGV[0]

if True:
  print("hello world!")

নোট করুন যে যখন আপনি দোভাষী প্রথম যুক্তিতে কোড লেখার অনুমতি দেন তখনই আপনি এটি করতে পারবেন। এখানে, -eএবং তার পরে সমস্ত কিছু রুবিকে 1 টি যুক্তি হিসাবে ভারব্যাটিম হিসাবে নেওয়া হয়। আমি যতদূর বলতে পারি, আপনি শেবাং কোডের জন্য ব্যাশ ব্যবহার করতে পারবেন না, কারণ bash -cকোডটি পৃথক যুক্তিযুক্ত হওয়া প্রয়োজন।

আমি শেবাং কোডের জন্য অজগর দিয়ে একই চেষ্টা করেছি:

#!/usr/bin/python -cexec("import sys,os\ntry: os.execlp('non-existing-interpreter', 'non-existing-interpreter', sys.argv[1])\nexcept: os.execlp('ruby', 'ruby', sys.argv[1])")

if true
  puts "hello world!"
end

তবে এটি খুব দীর্ঘ এবং লিনাক্স (কমপক্ষে আমার মেশিনে) শেবাংকে 127 টি অক্ষরে ছেদ করে। দয়া করে execনিউলাইনগুলি সন্নিবেশ করানোর জন্য ক্ষমা করুন কারণ পাইথন নিউলাইনগুলি importব্যতীত ট্রাই -এক্সেপ্টস বা গুলিকে অনুমতি দেয় না ।

আমি নিশ্চিত না যে এটি কতটা পোর্টেবল, এবং আমি বিতরণ করার কোডের মাধ্যমে এটি করব না। তবুও, এটি করণীয়। হয়তো কেউ তাড়াতাড়ি এবং মলিন ডিবাগিং বা কোনও কিছুর জন্য দরকারী বলে মনে করছেন।


2

যদিও এটি শেল স্ক্রিপ্টের মধ্যে দোভাষীকে নির্বাচিত করে না (এটি প্রতি মেশিনে এটি নির্বাচন করে) যদি আপনি স্ক্রিপ্টটি চালানোর চেষ্টা করছেন এমন সমস্ত মেশিনে প্রশাসনিক অ্যাক্সেস থাকে তবে এটি একটি সহজ বিকল্প।

পছন্দসই দোভাষী দের পথে নির্দেশ করতে একটি সিমিলিংক (বা চাইলে হার্ডলিঙ্ক) তৈরি করুন। উদাহরণস্বরূপ, আমার সিস্টেমে পার্ল এবং পাইথন / usr / বিনে রয়েছে:

cd /bin
ln -s /usr/bin/perl perl
ln -s /usr/bin/python python

হ্যাশব্যাংকে / বিন / পার্ল ইত্যাদির সমাধান করার জন্য একটি সিমিলিংক তৈরি করবে এটি স্ক্রিপ্টগুলিতেও পরামিতিগুলি পাস করার ক্ষমতা সংরক্ষণ করে।


1
+1 এটি এত সহজ। আপনি যেমন লক্ষ করেছেন, এটি প্রশ্নের পুরোপুরি উত্তর দেয় না তবে এটি ওপি যা চায় তা ঠিক করে দেবে বলে মনে হচ্ছে। যদিও আমি অনুমান করি যে env ব্যবহার করে প্রতিটি মেশিন ইস্যুতে মূল প্রবেশাধিকার পাওয়া যায়।
জো

0

আমি আজকের মতো একই সমস্যার মুখোমুখি হয়েছিলাম ( python3এক সিস্টেমে অজগরটির সংস্করণটি খুব পুরানো ছিল) এবং এখানে এমন একটি পদ্ধতির সাথে উপস্থিত হয়েছি যা এখানে আলোচনা করা থেকে কিছুটা আলাদা: এর "ভুল" সংস্করণটি ব্যবহার করুন পাইথনটি "ডান" একটিতে বুটস্ট্র্যাপ করুন। সীমাবদ্ধতাটি হ'ল পাইথনের কয়েকটি সংস্করণ নির্ভরযোগ্যভাবে পৌঁছানো দরকার, তবে এটি সাধারণত উদাহরণস্বরূপ অর্জন করা যায় #!/usr/bin/env python3

সুতরাং আমি যা করি তা আমার স্ক্রিপ্টটি দিয়ে শুরু করুন:

#!/usr/bin/env python3
import sys
import os

# On one of our systems, python3 is pointing to python3.3
# which is too old for our purposes. 'Upgrade' if needed
if sys.version_info[1] < 4:
    for py_version in ['python3.7', 'python3.6', 'python3.5', 'python3.4']:
        try:
            os.execlp(py_version, py_version, *sys.argv)
        except:
            pass # Deliberately ignore errors, pick first available version

এটি যা করে তা হ'ল:

  • কিছু গ্রহণযোগ্যতার মানদণ্ডের জন্য দোভাষী সংস্করণটি পরীক্ষা করুন
  • যদি গ্রহণযোগ্য না হয় তবে প্রার্থীদের সংস্করণগুলির একটি তালিকা দেখুন এবং যা উপলব্ধ রয়েছে তার মধ্যে এটির সাথে নিজেকে পুনরায় কার্যকর করুন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.