据我所知,execve()和family要求其参数数组的第一个参数与其第一个参数也指向的可执行文件相同.就是这样:
execve(prog, args, env);
Run Code Online (Sandbox Code Playgroud)
args [0]通常与prog相同.但我似乎无法找到有关其原因的信息.
我也明白可执行文件(呃,至少是shell脚本)在运行时总是把它们的调用路径作为第一个参数,但是我认为shell会把它放在那里,而execve()只会调用可执行文件使用第一个参数中给出的路径(上面的"prog"),然后在命令行上传递参数数组("args"从上面)....即,我不在命令上调用脚本args列表中的重复可执行路径行....
/bin/ls /bin/ls /home/john
Run Code Online (Sandbox Code Playgroud)
谁能解释一下?
Jon*_*ler 10
不要求第一个参数与可执行文件的名称有任何关系:
int main(void)
{
char *args[3] = { "rip van winkle", "30", 0 };
execv("/bin/sleep", args);
return 1;
}
Run Code Online (Sandbox Code Playgroud)
试试吧 - 在Mac上(三次测试后):
make x; ./x & sleep 1; ps
Run Code Online (Sandbox Code Playgroud)
第三轮的输出是:
MiniMac JL: make x; ./x & sleep 1; ps
make: `x' is up to date.
[3] 5557
PID TTY TIME CMD
5532 ttys000 0:00.04 -bash
5549 ttys000 0:00.00 rip van winkle 30
5553 ttys000 0:00.00 rip van winkle 30
5557 ttys000 0:00.00 rip van winkle 30
MiniMac JL:
Run Code Online (Sandbox Code Playgroud)
EBM评论:
Yeah, and this makes it even more weird. In my test bash script (the target of the execve), I don't see the value of what execve has in arg[0] anywhere -- not in the environment, and not as $0.
Revising the experiment - a script called 'bash.script':
#!/bin/bash
echo "bash script at sleep (0: $0; *: $*)"
sleep 30
Run Code Online (Sandbox Code Playgroud)
And a revised program:
int main(void)
{
char *args[3] = { "rip van winkle", "30", 0 };
execv("./bash.script", args);
return 1;
}
Run Code Online (Sandbox Code Playgroud)
This yields the ps output:
bash script at sleep (0: ./bash.script; *: 30)
PID TTY TIME CMD
7804 ttys000 0:00.11 -bash
7829 ttys000 0:00.00 /bin/bash ./bash.script 30
7832 ttys000 0:00.00 sleep 30
Run Code Online (Sandbox Code Playgroud)
There are two possibilities as I see it:
#!/bin/bash') line, orHow to establish the difference? I suppose copying the shell to an alternative name, and then using that alternative name in the shebang would tell us something:
$ cp /bin/bash jiminy.cricket
$ sed "s%/bin/bash%$PWD/jiminy.cricket%" bash.script > tmp
$ mv tmp bash.script
$ chmod +w bash.script
$ ./x & sleep 1; ps
[1] 7851
bash script at sleep (0: ./bash.script; *: 30)
PID TTY TIME CMD
7804 ttys000 0:00.12 -bash
7851 ttys000 0:00.01 /Users/jleffler/tmp/soq/jiminy.cricket ./bash.script 30
7854 ttys000 0:00.00 sleep 30
$
Run Code Online (Sandbox Code Playgroud)
This, I think, indicates that the kernel rewrites argv[0] when the shebang mechanism is used.
Addressing the comment by nategoose:
MiniMac JL: pwd
/Users/jleffler/tmp/soq
MiniMac JL: cat al.c
#include <stdio.h>
int main(int argc, char **argv)
{
while (*argv)
puts(*argv++);
return 0;
}
MiniMac JL: make al.c
cc al.c -o al
MiniMac JL: ./al a b 'c d' e
./al
a
b
c d
e
MiniMac JL: cat bash.script
#!/Users/jleffler/tmp/soq/al
echo "bash script at sleep (0: $0; *: $*)"
sleep 30
MiniMac JL: ./x
/Users/jleffler/tmp/soq/al
./bash.script
30
MiniMac JL:
Run Code Online (Sandbox Code Playgroud)
这表明shebang'#!/ path/to/program'机制,而不是任何程序,如Bash,调整的值argv[0].因此,当执行二进制时,argv[0]不调整值; 当通过shebang执行脚本时,参数列表由内核调整; argv[0]是在shebang上列出的二进制文件; 如果在shebang之后有争执,那就变成了argv[1]; 下一个参数是脚本文件的名称,后跟来自execv()或等效调用的任何剩余参数.
MiniMac JL: cat bash.script
#!/Users/jleffler/tmp/soq/al -arg0
#!/bin/bash
#!/Users/jleffler/tmp/soq/jiminy.cricket
echo "bash script at sleep (0: $0; *: $*)"
sleep 30
MiniMac JL: ./x
/Users/jleffler/tmp/soq/al
-arg0
./bash.script
30
MiniMac JL:
Run Code Online (Sandbox Code Playgroud)
它允许您指定要加载的可执行文件的确切路径,但也允许在诸如ps或 之类的工具中显示“美化”名称top。
execl("/bin/ls", "ls", "/home/john", (char *)0);
Run Code Online (Sandbox Code Playgroud)