恢复原始argv

Bai*_*ker 10 python command-line-arguments python-3.x

当显式调用脚本时python,它会argv被删除,因此这argv[0]是运行脚本的路径.如果被调用为python foo/bar.py甚至如此,就是这种情况python -m foo.bar.

我需要一种方法来恢复原始argv(即收到的原始python).不幸的是,它并不像前面那样容易sys.executable,sys.argv因为python foo/bar.py它不同于python -m foo.bar(隐式的PYTHONPATH不同,这可能是至关重要的,具体取决于你的模块结构).

更具体地说,在python foo/bar.py some other args和的情况下python -m foo.bar some other args,我正在寻找恢复['python', 'foo/bar.py', 'some', 'other', 'args']['python', '-m', 'foo.bar', 'some', 'other', 'args']分别.

我知道之前的问题:

但是这些似乎误解了炮弹是如何运作的,而答案却反映了这一点.我没有兴趣在解开外壳的工作(如评估壳VAR和功能都很好),我只是想在原来的argv给予python.

我发现的唯一解决方案是使用/proc/<PID>/cmdline:

import os
with open("/proc/{}/cmdline".format(os.getpid()), 'rb') as f:
  original_argv = f.read().split('\0')[:-1]
Run Code Online (Sandbox Code Playgroud)

这确实有效,但它只支持Linux(没有OSX,Windows支持似乎需要安装wmi软件包).幸运的是,对于我目前的用例,此限制很好.但是,拥有更清洁,跨平台的方法会更好.

这种/proc/<PID>/cmdline方法的工作原理让我希望python在运行脚本之前不会执行(至少不是syscall exec,但可能是exec内置的).我记得在某处读过所有这些参数处理(例如-m)都是在纯python中完成的,而不是C(这可以通过python -m this.does.not.exist产生看起来像是来自运行时的异常的事实来证实).所以,我冒昧地猜测纯python中的某个原始版本argv是可用的(也许这需要通过运行时初始化进行一些探索?).

tl; dr是否有一个交叉平台(内置,最好)的方式来获取原始argv传递给python(在它删除python可执行文件并转换-m blahblah.py)之前?

编辑从发现,我发现Py_GetArgcArgv,可以通过ctypes访问(在这里找到,链接到提到这种方法的几个 SO帖子):

import ctypes

_argv = ctypes.POINTER(ctypes.c_wchar_p)()
_argc = ctypes.c_int()

ctypes.pythonapi.Py_GetArgcArgv(ctypes.byref(_argc),
                                ctypes.byref(_argv))

argv = _argv[:_argc.value]
print(argv)
Run Code Online (Sandbox Code Playgroud)

现在这是操作系统可移植的,但不是python实现可移植的(只适用于cpython,ctypes如果你不需要它就很烦人).另外,特别是,我没有在Ubunutu 16.04(python -m foo.bar给我['python', '-m', '-m'])上得到正确的输出,但我可能只是犯了一个愚蠢的错误(我在OSX上得到了相同的行为).拥有一个完全可移植的解决方案(不深入研究ctypes)会很棒.

小智 5

Python 3.10 添加了sys.orig_argv,文档将其描述为最初传递给 Python 可执行文件的参数。如果这不完全是您正在寻找的内容,那么在这种情况或类似情况下它可能会有所帮助。

考虑了很多可能性,包括改变sys.argv,但我认为,这是明智的选择,作为最有效和无破坏性的选择。


J_H*_*J_H 0

您所说的问题是:

\n\n
    \n
  1. 用户使用环境变量和参数调用我的应用程序。
  2. \n
  3. 我想显示一个“像这样运行”的诊断,它将准确地重现当前运行的结果。
  4. \n
\n\n

至少有两种解决方案:

\n\n
    \n
  1. 放弃“复制”方面,因为原始的 bash 调用命令在便携式 python 应用程序中丢失了,而是追求“相同的效果”。
  2. \n
  3. 按照 Jean-Fran\xc3\xa7ois Fabre 的建议,使用包装器捕获原始调用命令。
  4. \n
\n\n

对于(1),你会愿意接受 [\'-m\', \'foo\'] 成为 [\'foo.py\'],甚至将其变成 [\'/some/dir/foo.py\']。 py\'] 以防 PYTHONPATH 可能引起麻烦。将 [\'a\', \'bc\'] 显示为"a" "b c",或更简洁地显示为a "b c",非常简单。如果像 SEED 这样的环境变量是命令行界面的重要组成部分,那么您还需要迭代 envp 并输出它们。为了真正的可重复性,您可以选择将输入参数转换为规范形式,与观察到的输入参数进行比较,如果它们不相同,则使用规范形式执行,因此无法使用“奇怪”的语法。

\n\n

使用(2),您可以将应用程序埋藏在一些不方便命名的文件中,广泛宣传包装程序,并享受在参数被修改之前看到它们的好处。

\n