(这个问题是在这里问的,但答案是特定于 Linux 的;我在 FreeBSD 和 NetBSD 系统上运行,这些系统(编辑:通常)没有/proc。)
Python 似乎很笨拙argv[0],因此您不会像 C 程序那样获得传递给进程的内容。公平地说,sh、bash 和 Perl 也好不到哪里去。有什么办法可以解决这个问题,这样我的 Python 程序就可以获得原始值吗?我在这个 FreeBSD 系统上有管理权限,可以做一些事情,比如更改每个人的默认 PATH 环境变量以指向包含 python2 和 python3 的目录之前的某个其他目录,但我无法控制创建/proc. 我有一个脚本来说明这个问题。首先,脚本的输出:
the C child program gets it right: arbitrary-arg0 arbitrary-arg1
the python2 program dumbs it down: ['./something2.py', 'arbitrary-arg1']
the python3 program dumbs it down: ['./something3.py', 'arbitrary-arg1']
the sh script dumbs it down: ./shscript.sh arbitrary-arg1
the bash script dumbs it down: ./bashscript.sh arbitrary-arg1
the perl script drops arg0: ./something.pl arbitrary-arg1
Run Code Online (Sandbox Code Playgroud)
...现在脚本:
#!/bin/sh
set -e
rm -rf work
mkdir work
cd work
cat > childc.c << EOD; cc childc.c -o childc
#include <stdio.h>
int main(int argc,
char **argv
)
{
printf("the C child program gets it right: ");
printf("%s %s\n",argv[0],argv[1]);
}
EOD
cat > something2.py <<EOD; chmod 700 something2.py
#!/usr/bin/env python2
import sys
print "the python2 program dumbs it down:", sys.argv
EOD
cat > something3.py <<EOD; chmod 700 something3.py
#!/usr/bin/env python3
import sys
print("the python3 program dumbs it down:", sys.argv)
EOD
cat > shscript.sh <<EOD; chmod 700 shscript.sh
#!/bin/sh
echo "the sh script dumbs it down:" \$0 \$1
EOD
cat > bashscript.sh <<EOD; chmod 700 bashscript.sh
#!/bin/sh
echo "the bash script dumbs it down:" \$0 \$1
EOD
cat > something.pl <<EOD; chmod 700 something.pl
#!/usr/bin/env perl
print("the perl script drops arg0: \$0 \$ARGV[0]\n")
EOD
cat > launch.c << EOD; cc launch.c -o launch; launch
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc,
char **argv,
char **arge)
{
int child_status;
size_t program_index;
pid_t child_pid;
char *program_list[]={"./childc",
"./something2.py",
"./something3.py",
"./shscript.sh",
"./bashscript.sh",
"./something.pl",
NULL
};
char *some_args[]={"arbitrary-arg0","arbitrary-arg1",NULL};
for(program_index=0;
program_list[program_index];
program_index++
)
{
child_pid=fork();
if(child_pid<0)
{
perror("fork()");
exit(1);
}
if(child_pid==0)
{
execve(program_list[program_index],some_args,arge);
perror("execve");
exit(1);
}
wait(&child_status);
}
return 0;
}
EOD
Run Code Online (Sandbox Code Playgroud)
我认为这里阻力最小的路径有点hacky,但可能适用于任何操作系统。基本上你双重包装了你的 Python 调用。首先(以 Python 3 为例),将Python3路径中的 替换为一个小的 C 程序,您知道该程序是可以信任的:
#include<stdlib.h>
#include<string.h>
int main(int argc, char **argv) {
// The python 3 below should be replaced by the path to the original one
// In my tests I named this program wrap_python so there was no problem
// but if you are changing this system wide (and calling the wrapper python3
// you can't leave this.
const char *const program = "python3 wrap_python.py";
size_t size = strlen(program) + 1; // Already added null character at end
for(int count = 0; count < argc; ++count)
size += strlen(argv[count]) + 1; // + 1 for space
char *cmd = malloc(size);
if(!cmd) exit(-1);
cmd[0] = '\0';
strcat(cmd, program);
for(int count = 1; count < argc; ++count) {
strcat(cmd, " ");
strcat(cmd, argv[count]);
}
strcat(cmd, " ");
strcat(cmd, argv[0]);
return system(cmd);
}
Run Code Online (Sandbox Code Playgroud)
你可以让它更快,但是嘿,过早优化?
请注意,我们正在调用一个名为wrap_python.py(可能您需要此处的完整路径)的脚本。我们想要传递 "true" argv,但我们需要在 Python 上下文中进行一些操作以使其透明。trueargv[0]作为最后一个参数传递,wrap_python.py是:
from sys import argv
argv[0] = argv.pop(-1)
print("Passing:", argv) # Delete me
exit(exec(open(argv[1]).read())) # Different in Python 2. Close the file handle if you're pedantic.
Run Code Online (Sandbox Code Playgroud)
我们的小包装器替换argv[0]为 C 包装器提供的包装器,将其从末尾删除,然后在相同的上下文中手动执行。具体来说__name__ == __main__是真的。
这将运行为
python3 my_python_script arg1 arg2 etc...
Run Code Online (Sandbox Code Playgroud)
您的路径现在将指向原始 C 程序。对此进行测试
import sys
print(__name__)
print("Got", sys.argv)
Run Code Online (Sandbox Code Playgroud)
产量
__main__
Got ['./wrap_python', 'test.py', 'hello', 'world', 'this', '1', '2', 'sad']
Run Code Online (Sandbox Code Playgroud)
注意我调用了我的程序wrap_python- 你想命名它python3。