如果我启动werkzeug开发服务器,那么它将在fork时失去-c cmd选项。
首先,这个进程不仅仅是被fork了。而是调用了一个新的Python解释器。
你所说的“它将失去-c cmd”是什么意思?是指cmd
字符串在argv中消失了吗?也就是:
$ python -c "import sys; print(sys.argv)"
['-c']
实际上,从
sys.argv
中无法访问
cmd
字符串。相关文档在
此处:
如果使用-c命令行选项运行命令,则argv[0]设置为字符串'-c'
文档没有对实际命令字符串进行评论。虽然该命令字符串显然作为Python解释器可执行文件的参数“发送”,但CPython实现似乎不会在
sys.argv
中公开此信息。我猜想,除非更改
sysmodule.c
的源代码,否则无法重构此信息。因此,如果您认为您依赖提取
cmd
,那么您应该找到另一种注入此信息的方法。
编辑:
实际命令字符串在函数
Py_Main()
中在
Modules/main.c
中被消耗。
wcscpy(command, _PyOS_optarg);
command
是稍后在main.c
中执行的命令。
命令行参数通过PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);
进行处理,它又调用了sysmodule.c
中的makeargvobject()
函数。后者在类似于for (i = 0; i < argc; i++) {}
的循环中将二进制参数数据转换为Python Unicode对象(至少在Python 3中是这样)。因此,在该循环中,必须(有意地)将argc
减去1才能忽略该命令。
也就是说,取消命令参数的魔法在于设置_PyOS_optind
,使得随后对PySys_SetArgv(argc-_PyOS_optind, argv+_PyOS_optind);
的调用建议比实际上小一个参数计数。
我没有完全跟进,但我想这些代码中的递减可能是有责任的:
if (command != NULL) {
/* Backup _PyOS_optind and force sys.argv[0] = '-c' */
_PyOS_optind--;
argv[_PyOS_optind] = L"-c";
}
编辑2:
通过对当前Python 3的以下补丁进行验证,确认了_PyOS_optind
的关键作用:
diff --git a/Modules/main.c b/Modules/main.c
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -679,9 +679,11 @@
}
if (command
/* Backup _PyOS_optind and force sys.argv[0] = '-c' */
_PyOS_optind--;
- argv[_PyOS_optind] = L"-c";
+ _PyOS_optind = 0;
+ //argv[_PyOS_optind] = L"-c";
}
if (module
测试:
$ ./python -c "import sys; print(sys.argv)"
['./python', '-c', 'import sys; print(sys.argv)']
cmd
真正的条带位置。在这个档案中,我已经发现了 Py_GetArgcArgv!然后我尝试了一些奇怪的东西,结果很奇怪:>>> python -c 'import ctypes; argv = ctypes.POINTER(ctypes.c_char_p)(); argc = ctypes.c_int(); ctypes.pythonapi.Py_GetArgcArgv(ctypes.byref(argc), ctypes.byref(argv)); print([argv[i] for i in xrange(0, argc.value)])'
['python', '-c', '-c']
- Mihail Krivushin