スクリプトを実行するインタプリタを動的に選択する方法はありますか? 2つの異なるシステムで実行されるスクリプトがあり、使用するインタプリタは2つのシステムの異なる場所にあります。結局私がすべきことは、切り替えるたびにハッシュバンラインを変更することでした。私がしたいことはロジックこれと同じです(このような正確な構成が不可能であることを知っています):
if running on system A:
#!/path/to/python/on/systemA
elif running on system B:
#!/path/on/systemB
#Rest of script goes here
あるいは、最初のインタプリタを使用しようとし、見つからない場合は、2番目のインタプリタを使用することをお勧めします。
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
手動ではなくプログラム的にPythonインタプリタへのパスを指定したいと思います。
答え1
実際のプログラムの正しいインタプリタを見つけるために、いつでもラッパースクリプトを作成できます。
#!/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
asにラッパーを保持しprogram
、実際のプログラムを別々に置くか、別の名前を使用してください。
#!/bin/bash
配列のためハッシュバンで使用しますflags
。可変個数のフラグなどを格納する必要がなく、それなしでもできる場合スクリプトは#!/bin/sh
。
答え2
いいえ、動作しません。これらの2文字は#!
ファイルの最初の2文字でなければなりません(解釈するif文の内容をどのように指定しますか?)。exec()
これは、実行するファイルがスクリプト(インタプリタが必要)かバイナリファイル(インタプリタが不要)であるかを判断するときに関数系列が検出する「魔法の数」を構成します。
shebangラインの形式は非常に厳格です。インタプリタへの絶対パスと最大1つの引数が必要です。
あなたは何ですかできるする必要があるのは、次のことです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
別の明確な方法は、GNU autotools(またはいくつかのより単純なテンプレートシステム)を使用してインタプリタを見つけ、スクリプトが各システムにインストールされたときに実行されるステップでファイルへの正しいパスを指定することです。
明示的なインタプリタを使用してスクリプトを実行することもできますが、これは明らかに避けたいことです。
$ sed -f script.sed
答え3
多言語(2言語の組み合わせ)で書くこともできます。 /bin/sh 存在が保証されます。
欠点は、コードが見苦しいことです。ただし、env
存在しない場合、または/usr/bin/env以外の場所に存在する場合に使用できます。本当に素敵な選択をしたいときにも使えます。
スクリプトの最初の部分は、/bin/sh をインタプリタとして使用して実行するときに使用するインタプリタを決定しますが、正しいインタプリタによって実行されると無視されます。私たちはこれを使用して、シェルがexec
最初の部分を通過するのを防ぎます。
Pythonの例:
#! /bin/sh -
''':'
# Python thinks this is a string, docstring unfortunately.
# The shell just ran the no-op : command.
find_best_python ()
{
for candidate in pypy3 pypy python3 python; do
if "$candidate" -c '' 2>/dev/null; then
echo "$candidate"
return
fi
done
echo >&2 "Can't find any Python"
false
}
interpreter="$(find_best_python)" || exit # Replace with something fancier.
# Re-run the rest of the script with the chosen interpreter:
exec "$interpreter" "$0" "$@"
'''
print("Python code goes here")
答え4
これはシェルスクリプトでインタプリタを選択しませんが(各システムのインタプリタを選択します)、スクリプトを実行したいすべてのシステムへの管理アクセス権がある場合は簡単です。
必要なインタプリタパスを指すシンボリックリンク(または必要に応じてハードリンク)を作成します。たとえば、私のシステムでは、PerlとPythonは/ usr / binにあります。
cd /bin
ln -s /usr/bin/perl perl
ln -s /usr/bin/python python
hashbangが/ bin / perlなどを解析できるようにシンボリックリンクが作成されます。また、パラメータをスクリプトに渡す機能も維持されます。