zsh如何解释shebangs中的非绝对路径? (WAS:为什么python3 -i为什么在shebang中允许使用非绝对路径?)

时间:2018-07-13 04:11:39

标签: zsh shebang

我最近发现Python的-i参数,脚本完成后drops into interactive mode。很整齐!

$ cat test.py
#!python3 -i

x=5
print('The value of x is ' + str(x))
$ ./test.py
The value of x is 5
>>> print(str(x+1))
6
>>> 
zsh: suspended  ./test.py

但是,当我尝试将此脚本复制到在完成时终止的版本时,它将失败:

$ cat test1.py
#!python3

x=5
print('The value of x is ' + str(x))
$ ./test.py
/usr/local/Cellar/python3/3.6.3/Frameworks/Python.framework/Versions/3.6/Resources/Python.app/Contents/MacOS/Python: can't open file '
x=5
print('The value of x is ' + str(x))
': [Errno 2] No such file or directory

从某些further reading中,我发现自己最初犯了一个错误,而#!/usr/bin/env python3是正确的shebang。

但是,我很好奇为什么给我python3标志时,到-i的非绝对路径只能成功 。我猜想这一定与zsh解释非绝对shebang的方式有关,但是我还不知道如何进行调查。

系统设置:MacOS 10.12.6,iTerm2 3.1.6,zsh 5.2。 which python3给出/usr/local/bin/python3,该目录位于$PATH上。

有趣的是,我在sh上没有得到相同的行为:

$ sh
sh-3.2$ cat test.py
#!python3

x=5
print('The value of x is ' + str(x))
sh-3.2$ ./test.py
sh: ./test.py: python3: bad interpreter: No such file or directory

我有一些评论建议这与CWD或权限有关。 python3不在我的CWD中,并且两个文件都具有执行权限:

$ ls -al | grep 'py' | awk '{print $1, $10}'
-rw------- .python_history
-rwxr-xr-x test.py
-rwxr-xr-x test1.py

1 个答案:

答案 0 :(得分:1)

您的内核将不会执行脚本,除非解释器是

  • 指定为绝对路径,或
  • 指定为相对于当前工作目录的路径

然后,如果内核拒绝执行该脚本,则您的外壳可能接管并尝试执行该脚本,并根据其自身的规则解释shebang行(例如在{{ 1}}。

$PATH确实尝试执行此操作。 zsh不会。

然而,sh解释shebang(以及随后的几行)的方式真的很奇怪。看起来总是在命令名称后加上单个参数。看看它能做什么:

zsh

查看如何将$ cat test.py #!python3 -b -i x=5 print('The value of x is ' + str(x)) $ strace -f -e execve zsh execve("/bin/zsh", ["zsh"], 0x7ffd35c9e198 /* 78 vars */) = 0 host% ./test.py strace: Process 5510 attached [pid 5510] execve("./test.py", ["./test.py"], 0x558ec6e46710 /* 79 vars */) = -1 ENOENT (No such file or directory) [pid 5510] execve("/usr/bin/python3", ["python3", "-b -i", "./test.py"], 0x558ec6e46710 /* 79 vars */) = 0 [pid 5510] execve("/usr/lib/python-exec/python3.4/python3", ["/usr/lib/python-exec/python3.4/p"..., "-b -i", "./test.py"], 0x7fffd30eb208 /* 79 vars */) = 0 Unknown option: - usage: /usr/lib/python-exec/python3.4/python3 [option] ... [-c cmd | -m mod | file | -] [arg] ... Try `python -h' for more information. [pid 5510] +++ exited with 2 +++ --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=5510, si_uid=1000, si_status=2, si_utime=0, si_stime=0} --- host% +++ exited with 2 +++ 作为参数传递。将两个开关["python3", "-b -i", "./test.py"]-b组合在一起对我来说似乎很违反直觉,但这是zsh所做的。 Python显然不理解这一点。

当没有参数时,确切的行为取决于程序名称后是否有空格,但是在两种情况下都很奇怪。自己与-i进行检查,因为您不会相信我。

据我了解,对shebang行的zsh处理只是越野车。