zsh 如何解释 shebang 中的非绝对路径? (WAS:为什么 python3 -i 允许在 shebang 中使用非绝对路径?)
How does zsh interpret non-absolute paths in shebangs? (WAS: Why does python3 -i permit non-absolute paths in 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。
但是,我很好奇为什么当我给出 -i
标志时,python3
的非绝对路径 仅 成功。我想这一定与 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 , }'
-rw------- .python_history
-rwxr-xr-x test.py
-rwxr-xr-x test1.py
除非解释器是
,否则您的内核将不会执行脚本
- 指定为绝对路径,或
- 指定为相对于当前工作目录的路径
然后如果内核拒绝执行脚本,您的 shell 可能会 接管并尝试执行它,根据自己的规则解释 shebang 行(比如在 $PATH
中找到可执行文件)。
zsh
确实尝试这样做。 sh
没有。
但是 zsh
解释 shebang(可能还有后续行)的方式真的很奇怪。看起来它总是希望在命令名称后有一个 单个 参数。看看它的作用:
$ 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
和 -i
放在一起似乎非常违反直觉,但这就是 zsh 所做的。 Python 显然没看懂
当没有参数时,确切的行为取决于程序名称 后是否有space,但在这两种情况下都很奇怪。亲自 strace
检查一下,因为你不会相信我。
据我了解,shebang 行的 zsh 处理只是错误。
我最近发现 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。
但是,我很好奇为什么当我给出 -i
标志时,python3
的非绝对路径 仅 成功。我想这一定与 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 , }'
-rw------- .python_history
-rwxr-xr-x test.py
-rwxr-xr-x test1.py
除非解释器是
,否则您的内核将不会执行脚本- 指定为绝对路径,或
- 指定为相对于当前工作目录的路径
然后如果内核拒绝执行脚本,您的 shell 可能会 接管并尝试执行它,根据自己的规则解释 shebang 行(比如在 $PATH
中找到可执行文件)。
zsh
确实尝试这样做。 sh
没有。
但是 zsh
解释 shebang(可能还有后续行)的方式真的很奇怪。看起来它总是希望在命令名称后有一个 单个 参数。看看它的作用:
$ 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
和 -i
放在一起似乎非常违反直觉,但这就是 zsh 所做的。 Python 显然没看懂
当没有参数时,确切的行为取决于程序名称 后是否有space,但在这两种情况下都很奇怪。亲自 strace
检查一下,因为你不会相信我。
据我了解,shebang 行的 zsh 处理只是错误。