2010-06-12 122 views
5

我知道execve()和family要求其参数数组的第一个参数与第一个参数指向的可执行文件相同。也就是,在此:为什么第一个参数execve()必须是可执行文件的路径

execve(prog, args, env); 

args [0]通常与prog相同。但我似乎无法找到关于这是为什么的信息。我也明白,可执行文件(呃,至少是shell脚本)在运行时总是有它们的调用路径作为第一个参数,但我会认为shell会做这件事,而execve()会只需使用第一个参数(上面的“prog”)中给出的路径调用可执行文件,然后像在命令行中那样传递参数数组(从上面的“args”)....即,我没有调用命令行上的脚本在args列表中具有重复的可执行文件路径....

/bin/ls /bin/ls /home/john 

有人可以解释吗?

回答

4

它允许您指定要加载的可执行文件的确切路径,但也允许在诸如pstop之类的工具中显示“美化”名称。

execl("/bin/ls", "ls", "/home/john", (char *)0); 
+2

您需要双引号;并可能是一个空char *来终止参数列表,假设您使用的是execl()。 – 2010-06-12 03:28:26

+0

我会接受你的话,但有趣的是,我创建了一个测试,执行一个简单的bash脚本,吐出$ 0,甚至当我使用“美化”程序名时,$ 0仍然是完整路径execve()的第一个参数,那么,我假设)。 – EBM 2010-06-12 03:30:32

+0

@Johnathan:怪罪Python。 – 2010-06-12 03:31:19

4

根据this,作为程序名称的第一个参数是一个自定义。

由定制时,第一元件应该是 执行的程序的(对于 例如,路径的最后成分)

提到的名称,这些值可以不同。例如,如果程序是从符号链接启动的。程序名称可能与用于启动它的链接不同。

而且,你是对的。 shell通常会设置第一个参数。然而,在这种情况下,execve的使用完全避开了shell - 这就是为什么你需要自己设置它。

+0

感谢您的回答 – EBM 2010-06-12 03:28:54

9

不要求第一的论点承担任何有关的可执行文件的名称:

int main(void) 
{ 
    char *args[3] = { "rip van winkle", "30", 0 }; 
    execv("/bin/sleep", args); 
    return 1; 
} 

试试吧 - 在Mac上(后三项测试):

make x; ./x & sleep 1; ps 

在第三运行的输出是:

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: 

EBM评论:

呀,这使它更加怪异。在我的测试bash脚本(execve的目标)中,我没有看到execve在arg [0]中的任何地方的价值 - 而不是在环境中,而不是$ 0。

修改实验 - 一个名为'bash的脚本。脚本':

#!/bin/bash 

echo "bash script at sleep (0: $0; *: $*)" 
sleep 30 

而修订的计划:

int main(void) 
{ 
    char *args[3] = { "rip van winkle", "30", 0 }; 
    execv("./bash.script", args); 
    return 1; 
} 

这就产生ps输出:

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 

有两种可能性,因为我看到它:

  1. 内核在通过脚本执行脚本时会对命令行进行操作shebang('#!/bin/bash')行,或
  2. Bash本身与其参数列表沾在一起。

如何建立区别?我想复制壳的替代名称,然后使用在家当替代名称会告诉我们一些东西:

$ 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 
$ 

此,我认为,表示所使用的家当机制,当内核重写argv[0]


解决因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: 

这表明它是家当机制,而不是任何程序,如猛砸,即调整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: 
+0

是的,这使得它更奇怪。在我的测试bash脚本(execve的目标)中,我没有看到execve在arg [0]中的任何地方的价值 - 而不是在环境中,而不是$ 0。 – EBM 2010-06-12 05:41:13

+0

制作脚本'#!/ home/me/print_args'并编写一个简单的打印arg程序,以确保谁使用'argv [0]'摆弄' – nategoose 2010-06-13 00:58:18

0

允许程序有许多名字和工作使用其名字,它被称为略有不同视。

成像微不足道的程序,例如print0.c编译成print0:

#include <stdio.h> 
int main(int argc, char **argv) 
{ 
    printf("%s\n",argv[0]); 
    return 0; 
} 

运行它,./print0将打印./print0做一个符号链接例如打印1,现在使用名称./print1来运行它 - 它会打印“./print1”。

现在,这是一个符号链接。但是使用exec *()函数,你可以明确地告诉程序的名字。

来自* NIX的神器,但很高兴有。

+0

请参阅我对Jonathan Leffler的评论 - 使用测试bash脚本作为目标execve调用,arg [0]不会出现在任何地方。也许一个C程序以不同的方式获得它的参数,但至少对于一个bash脚本来说,你解释的这个特性似乎是不存在的。 – EBM 2010-06-12 10:52:15

+0

是的,shell的exec不允许这样做。人们不得不使用符号链接以不同的名称调用程序。 – Dummy00001 2010-06-12 13:43:36

相关问题