典型的 Unix/Linux 程序接受命令行输入作为参数计数 ( int argc
) 和参数向量 ( char *argv[]
)。第一个元素argv
是程序名称 - 后面是实际参数。
为什么程序名称作为参数传递给可执行文件?是否有任何程序使用自己的名称的示例(也许是某种exec
情况)?
答案1
首先,请注意这argv[0]
不一定是程序名称。这是调用者argv[0]
在系统调用中放入的内容execve
(例如,参见Stack Overflow 上的这个问题)。 ( 的所有其他变体exec
都不是系统调用,而是 的接口execve
。)
例如,假设以下情况(使用execl
):
execl("/var/tmp/mybackdoor", "top", NULL);
/var/tmp/mybackdoor
是执行但argv[0]
设置为 的内容top
,这就是ps
or (真实的)top
将显示的内容。看这个答案有关更多信息,请访问 U&L SE。
抛开所有这些不谈:在诸如 之类的奇特文件系统出现之前/proc
,argv[0]
是进程了解自己名称的唯一方法。那有什么好处呢?
- 一些程序根据调用它们的名称(通常通过符号或硬链接,例如BusyBox 的实用程序;该问题的其他答案中提供了更多示例)。
- 此外,通过 syslog 记录的服务、守护进程和其他程序通常会将其名称添加到日志条目中;如果没有这个,事件跟踪将变得几乎不可行。
答案2
充足:
- Bash 运行在POSIX模式什么
argv[0]
时候sh
。当argv[0]
以 开头时,它作为登录 shell 运行-
。 vi
当以、view
、evim
、eview
、ex
、vimdiff
等方式运行时,Vim 的行为有所不同。- Busybox,正如已经提到的。
- 在以 systemd 作为 init 的系统中,
shutdown
、reboot
等是符号链接到systemctl
。 - 等等。
答案3
从历史上看,argv
它只是指向命令行“单词”的指针数组,因此从第一个“单词”开始是有意义的,它恰好是程序的名称。
并且有相当多的程序根据用于调用它们的名称而表现不同,因此您只需创建指向它们的不同链接并获取不同的“命令”。我能想到的最极端的例子是忙碌盒, 哪个其行为类似于几十个不同的“命令”,具体取决于它的调用方式。
编辑: Unix 第一版的参考资料,根据要求
例如可以从主要的cc
该功能argc
并argv
已被使用。这壳将参数复制到循环部分的parbuf
内部newarg
,同时以与参数相同的方式处理命令本身。 (当然,稍后它只执行第一个参数,即命令的名称)。看来execv
那时亲戚还不存在。
答案4
除了程序根据调用方式改变其行为之外,我发现argv[0]
打印程序的使用很有用,如下所示:
printf("Usage: %s [arguments]\n", argv[0]);
这会导致使用消息始终使用调用它的名称。如果程序被重命名,其使用信息也会随之改变。它甚至包括调用它的路径名:
# cat foo.c
#include <stdio.h>
int main(int argc, char **argv) { printf("Usage: %s [arguments]\n", argv[0]); }
# gcc -Wall -o foo foo.c
# mv foo /usr/bin
# cd /usr/bin
# ln -s foo bar
# foo
Usage: foo [arguments]
# bar
Usage: bar [arguments]
# ./foo
Usage: ./foo [arguments]
# /usr/bin/foo
Usage: /usr/bin/foo [arguments]
这是一个很好的接触,特别是对于可能遍布各处的小型专用工具/脚本而言。
这在 GNU 工具中似乎也是常见的做法,ls
例如:
% ls --qq
ls: unrecognized option '--qq'
Try 'ls --help' for more information.
% /bin/ls --qq
/bin/ls: unrecognized option '--qq'
Try '/bin/ls --help' for more information.