Как zsh интерпретирует неабсолютные пути в shebangs? (WAS: почему python3 -i разрешает неабсолютные пути в shebang?)

Недавно я обнаружил аргумент -i для Python, который переходит в интерактивный режим после завершения сценария. Довольно аккуратно!

$ 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

Из некоторого дальнейшего чтения я обнаружил, что изначально сделал ошибку, и #!/usr/bin/env python3 - правильный шебанг.

Однако мне любопытно, почему неабсолютный путь к python3 успешен только, когда я выставляю флаг -i. Я предполагаю, что это должно быть как-то связано с тем, как zsh интерпретирует неабсолютные шебанги, но я не знаю достаточно, чтобы знать, как это исследовать.

Настройка системы: 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

person scubbo    schedule 13.07.2018    source источник
comment
Python не имеет к этому никакого отношения. Ваша оболочка отвечает за shebang.   -  person n. 1.8e9-where's-my-share m.    schedule 13.07.2018
comment
Хорошо, честно - позвольте мне перефразировать свой вопрос. Почему zsh ведет себя так, что неабсолютный путь к python3 иногда работает так, как ожидалось, но не другие?   -  person scubbo    schedule 13.07.2018
comment
Вы неправильно проводите свой эксперимент. Попробуйте еще раз, не меняя текущий рабочий каталог. Shebang работает (1) с абсолютным путем и (2) с путем относительно CWD. $PATH или аргументы командной строки не играют здесь роли.   -  person n. 1.8e9-where's-my-share m.    schedule 13.07.2018
comment
Я понятия не имею, что случилось с test1. Нет разрешения на выполнение?   -  person n. 1.8e9-where's-my-share m.    schedule 13.07.2018
comment
Я получил тот же результат с -i или без него. поскольку очевидно, что это не должно быть причиной для поиска интерпретатора при выполнении вашего кода. и сохранил мое разрешение файла 777. Это ваша локальная среда, ничего общего с python   -  person Mr. J    schedule 13.07.2018
comment
@ n.m., извините, я не понимаю ваш комментарий - я не менял свой cwd, нет cd в примерах выше. Я добавил фрагмент, демонстрирующий, что python3 отсутствует на моем cwd и что test1.py имеет разрешение на выполнение   -  person scubbo    schedule 13.07.2018
comment
Извините, я не совсем точен, подробности смотрите в моем ответе.   -  person n. 1.8e9-where's-my-share m.    schedule 13.07.2018


Ответы (1)


Ваше ядро ​​не будет выполнять сценарий, если интерпретатор не

  • указан как абсолютный путь, или
  • указывается как путь относительно текущего рабочего каталога

Затем, если ядро ​​отказывается выполнять сценарий, ваша оболочка может взять на себя управление и попытаться выполнить его в любом случае, интерпретируя строку 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 явно этого не понимает.

Когда аргументов нет, точное поведение зависит от того, стоит ли после имени программы пробел, но в любом случае является странным. Проверьте это с strace сами, потому что вы мне не поверите.

Насколько я понимаю, обработка строки shebang в zsh просто глючна.

person n. 1.8e9-where's-my-share m.    schedule 13.07.2018