避免意外将 Python 脚本作为 Bash 脚本执行

避免意外将 Python 脚本作为 Bash 脚本执行

我喜欢直接在 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/python3py“扩展”:

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无论如何都会被使用。


个人观点

这种方法很有效,你甚至可能会喜欢它,但我并不喜欢它。我的理由如下:

  1. 如果你有时忘记了shebang,你也会忘记py“扩展”。坦率地说,在我看来,你应该算了吧,因为……

  2. tool.py可执行文件的“扩展名”很丑陋。想象一下,您用 C 或其他语言重写了您的程序;您要更改文件名吗?如果是这样,tool.py则必须更新所有使用的文件。如果文件tool从一开始就命名,那么全世界就可以开始使用新版本,甚至可能没有意识到已经发生了变化。依靠魔法字节(如 shebang)可以轻松实现这一点。

相关内容