我喜欢直接在 bash 中运行我的 python 脚本,就像这样
$ ./script.py
但有时我会忘记shebang行#!/usr/bin/env python3
,并且它可能会覆盖名为的文件(np
如果脚本有的话)import numpy as np
(并且如果在运行ImageMagick import 命令时单击几次)。
我该怎么做才能避免意外将 python 脚本作为 bash 脚本执行?有没有办法(shell 选项或 .bashrc 脚本)阻止 bash 将扩展名为“.py”的脚本作为 bash 脚本执行?或者实际上阻止任何没有 shebang 行的脚本的执行?
(该问题在 StackOverflow 上被关闭,因为它与编程的相关性并不如社区所希望的那样。)
答案1
如果我没记错的话,这种以 shell 脚本形式执行的回退功能在多个地方实现;当任何程序使用 execv() 时,glibc 会在内部执行此操作,但 shell 本身也可能执行相同的操作(我还没有检查 bash 如何处理这种情况)。至少对于 glibc 来说,据我所知,没有简单的方法可以禁用它(除非修补 glibc)。
我自己的做法是删除 ImageMagickimport
命令(它在 7.x 中已被magick
超级命令取代,所以应该被称为magick import
),并用自定义的 ~/bin/import 代替它,它会弹出一个愚蠢的警告,然后终止父进程而不是做任何有害的事情。
#!/bin/bash
file=$(readlink /proc/$PPID/fd/254)
echo "You forgot #! in $file." >&2
kill $PPID
答案2
可能的方法
在 Linux 中,您可以使用binfmt_misc
。请参阅文档, 它指出:
首先你必须安装
binfmt_misc
:mount binfmt_misc -t binfmt_misc /proc/sys/fs/binfmt_misc
但 Debian 或 Ubuntu(以及可能使用 systemd 的其他发行版)会自动安装它。如果mount | grep binfmt_misc
显示binfmt_misc
已安装,/proc/sys/fs/binfmt_misc
则表示已设置。
您可以通过调用以下命令手动分配/usr/bin/python3
给py
“扩展”:
echo ':py:E::py::/usr/bin/python3:' | sudo tee /proc/sys/fs/binfmt_misc/register
为了完整起见,您可以按照以下方式手动取消注册:
echo -1 | sudo tee /proc/sys/fs/binfmt_misc/py
为了使分配在重启后继续生效(如果您的 Linux 使用systemd-binfmt.service
),请创建一个包含以下内容的py.conf
文件:/etc/binfmt.d/
# Run .py files with /usr/bin/python3
:py:E::py::/usr/bin/python3:
请man 5 binfmt.d
参阅详情。
我的测试表明,如果有的话,定义的解释器会使用 shebang 获胜。换句话说:应用上述内容后,文件中的 shebang*.py
将变得无关紧要,/usr/bin/python3
无论如何都会被使用。
个人观点
这种方法很有效,你甚至可能会喜欢它,但我并不喜欢它。我的理由如下:
如果你有时忘记了shebang,你也会忘记
py
“扩展”。坦率地说,在我看来,你应该算了吧,因为……tool.py
可执行文件的“扩展名”很丑陋。想象一下,您用 C 或其他语言重写了您的程序;您要更改文件名吗?如果是这样,tool.py
则必须更新所有使用的文件。如果文件tool
从一开始就命名,那么全世界就可以开始使用新版本,甚至可能没有意识到已经发生了变化。依靠魔法字节(如 shebang)可以轻松实现这一点。