dkv*_*dkv 17 shell shell-script exec shebang interpreter
有没有办法动态选择正在执行脚本的解释器?我有一个在两个不同系统上运行的脚本,我想使用的解释器位于两个系统上的不同位置。我最终不得不在每次切换时更改 hashbang 行。我想做一些与此逻辑等效的事情(我意识到这种确切的构造是不可能的):
if running on system A:
#!/path/to/python/on/systemA
elif running on system B:
#!/path/on/systemB
#Rest of script goes here
Run Code Online (Sandbox Code Playgroud)
或者更好的是这样,以便它尝试使用第一个解释器,如果没有找到,则使用第二个解释器:
try:
#!/path/to/python/on/systemA
except:
#!path/on/systemB
#Rest of script goes here
Run Code Online (Sandbox Code Playgroud)
显然,我可以
根据我所在的位置/path/to/python/on/systemA myscript.py
或
/path/on/systemB myscript.py根据我所在的位置来执行它
,但我实际上有一个启动的包装脚本myscript.py,所以我想以编程方式而不是手动指定 python 解释器的路径。
ilk*_*chu 28
您始终可以制作一个包装脚本来为实际程序找到正确的解释器:
#!/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" "$@"
Run Code Online (Sandbox Code Playgroud)
将包装器保存在用户的PATHas 中program,并将实际程序放在一边或使用其他名称。
#!/bin/bash由于flags数组,我在 hashbang 中使用。如果您不需要存储可变数量的标志等并且可以不用它,则该脚本应该可移植地使用#!/bin/sh.
Kus*_*nda 26
不,那行不通。这两个字符#!绝对需要是文件中的前两个字符(无论如何,您将如何指定解释 if 语句的内容?)。这构成了exec()函数族在确定它们将要执行的文件是脚本(需要解释器)还是二进制文件(不需要解释器)时检测到的“幻数” 。
shebang行的格式相当严格。它需要有一个到解释器的绝对路径和最多一个参数。
你可以做的是使用env:
#!/usr/bin/env interpreter
Run Code Online (Sandbox Code Playgroud)
现在,路径env是一般 /usr/bin/env,但在技术上这是没有保证。
这允许您调整PATH每个系统上的环境变量,以便找到interpreter(无论是它bash,python还是perl您拥有的任何东西)。
这种方法的缺点是不可能将参数可移植地传递给解释器。
这意味着
#!/usr/bin/env awk -f
Run Code Online (Sandbox Code Playgroud)
和
#!/usr/bin/env sed -f
Run Code Online (Sandbox Code Playgroud)
不太可能在某些系统上工作。
另一个明显的方法是使用 GNU 自动工具(或一些更简单的模板系统)来查找解释器并将正确的路径放入文件中./configure,这将在每个系统上安装脚本时运行。
也可以使用显式解释器运行脚本,但这显然是您要避免的:
$ sed -f script.sed
Run Code Online (Sandbox Code Playgroud)
Osk*_*kog 12
您还可以编写多语言(组合两种语言)。/bin/sh 保证存在。
这有丑陋代码的缺点,也许某些/bin/shs 可能会混淆。但是它可以在env不存在或存在于 /usr/bin/env 之外的其他地方时使用。如果您想做一些漂亮的选择,也可以使用它。
脚本的第一部分确定在 /bin/sh 作为解释器运行时使用哪个解释器,但在由正确的解释器运行时被忽略。使用exec以防止shell比第一部分运转更。
蟒蛇示例:
#!/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" "$@"
'''
Run Code Online (Sandbox Code Playgroud)