我正在用 C 语言编写一个 shell,但我无法理解execvp(filepath,argv)
所需的 filepath 参数。
如果键入的用户想要在其当前目录中运行ls -a
...比方说/home/user1
...在所述目录中运行ls
的filepath
和argv
是什么?
filepath
是从/home/user1
执行命令的目录,还是命令的位置/bin/ls
?
execvp()
的filepath
参数可以采用两种形式之一 - 它包含斜杠或不包含斜杠。
带斜杠
filepath
参数指定可执行文件的路径名,即绝对名称(以斜杠开头(或相对名称(不以斜杠开头,但包含斜杠(。 execvp()
函数不对参数进行任何更改,并且程序将执行(或不执行(,假设命名的文件存在且可执行。
不带斜杠
filepath
参数指定一个"简单"名称,例如 ls
。 然后,excevp()
函数寻求执行名称ls
在$PATH
环境变量中列出的目录之一中找到的程序。 execvp()
中的p
用于"路径",就像在路径查找中一样。
应用理论
如果用户键入 ls -a
到 shell,则执行该命令的正常方法是创建一个字符指针数组,等效于:
char *argv[] = { "ls", "-a", 0 };
execvp(argv[0], argv);
execvp()
现在将执行基于路径的分析,并尝试从 $PATH
中列出的目录之一执行ls
。
如果用户键入 /bin/ls -a
到 shell,则执行它的正常方法是创建一个字符指针数组,等效于:
char *argv[] = { "/bin/ls", "-a", 0 };
execvp(argv[0], argv);
execvp()
现在将执行指定的绝对路径名,因为这是用户请求的(而不是,比如说,/usr/bin/ls
或/usr/local/bin/ls
(。
请注意,处理实际上是相同的 — 您将命令行拆分为单词;每个单词都成为字符指针数组的一个元素,该数组以 null 指针结尾,您将第一个单词作为 'filepath' 参数传递给execvp()
,并将整个数组作为第二个参数传递给
显然,shell 可以缓存实际可执行文件的位置,许多 shell 都可以缓存,这样execvp()
就不必尝试查找程序(并且 shell 不会调用execvp()
但通常使用可执行文件的绝对路径名调用 execv()
。 但这不是必需的;这是一种优化。
还要注意,没有什么可以阻止你这样做:
char *argv[] = { "/honky/tonk/toys", "-a", 0 };
execvp("ls", argv);
现在argv[0]
应该是"/honky/tonk/toys"
而不是ls
,因为它运行的是ls
可执行文件。 您在/proc
中找到的内容取决于您的系统是否/proc
(例如,Mac OS X 不支持它(,但指向二进制文件的符号链接应该是指向/bin/ls
的链接。 在 Linux 上,你很容易发现 ps
报告二进制名称 ( ls
(,即使/proc/PID/cmdline
包含原始参数(所以argv[0]
是/honky/tonk/toys
(。 这是否好取决于你的观点,但全世界都不是Linux。
要在当前目录中运行/bin/ls -a,您需要:
与 C 程序启动时传递到 main()
argv
相同,但NULL
终止,路径与 argv[0]
相同。
char* argv[] = { "/bin/ls", "-a", NULL };
execvp(argv[0], argv);