为什么 *nix 命令行允许通过相对于当前目录的路径执行?



很长一段时间以来,我的印象是 *NIX shell 不支持通过相对于当前目录的路径运行可执行文件。此外,还有许多帖子解释了为什么在路径中使用工作目录是一种不好的做法。仍然很容易看出以下示例有效:

% cat<<EOF > temp/a
? #!/bin/sh
? echo "Hello looser!"
? EOF
% chmod 750 temp/a
% temp/a
Hello looser!

(我在 CentOS 和 OSX 上测试过)。

为什么有效?

Upd:这不是纯粹的学术问题,我遇到过二进制文件通过完整路径运行的情况,并且上述方式的工作方式不同。

Upd 2:libcexecv接受绝对路径和相对路径,没有问题。因此,在无法运行的情况下支持subpath/exeexe看起来像 bash 和 tcsh 共有的 shell 功能。背后一定有什么逻辑吧??

您始终可以通过指定程序的相对路径来执行程序。没有要求必须使用绝对路径。实际上,您执行程序的方式很常见。

如果你在没有/的情况下编写command,则 shell 会$PATH搜索该命令。

如果使用相对目录编写dir/command,则会出现/,并且 shell不会搜索$PATH。它相对于当前目录解释它。dir/command总是决心./dir/command.

.放在$PATH中是危险的,因为您可能键入打算运行/usr/bin/commandcommand,但如果它存在于当前目录中,则实际上会得到./command。事实上,不仅仅是.是危险的:任何相对路径都是危险的。$PATH应该只包含绝对路径。


所以,你是说相对路径应该隐式地以当前目录为前缀,在特殊情况下,当相对路径为空时,应被视为$PATH搜索的方向?

是的,你可以这么说。但我更喜欢重新构建它。更好的思考方法是了解shell在做什么,而不是内核在做什么。

解释相对路径由内核隐式处理。当 shell 执行系统调用(如execve("dir/command", ...))来执行程序时,内核知道父进程的当前目录并解析相对于它的dir/command。外壳不必首先将路径转换为绝对路径。内核可以处理绝对路径和相对路径。

内核对$PATH一无所知。这是一个外壳结构。请记住,外壳是一个更高级别的软件。shell 决定,如果您键入一个没有/的简单命令名称,它不会简单地将该命令传递给内核。如果是这样,键入cat将简单地执行./cat。没有人想要这样。

相反,shell 决定缺少/意味着它将在$PATH中搜索命令。它会搜索/bin/usr/bin$HOME/bin等。如果您在$PATH中列出了.,那么它也会搜索当前目录 - 不要这样做!您不希望它运行./cat.没有,先生。

如果 shell 在$PATH中找到可执行文件,则它会将其转换为绝对路径名并将其传递给内核。内核看到execve("/usr/bin/cat", ...).


如果是这样,并且您从一些正式规范中知道它,我将不胜感激。我确实需要确切地知道。

请参阅 bash 手册页:

如果命令名称不包含斜杠,shell 会尝试查找它。

如果名称...不包含斜杠,bash 在PATH的每个元素中搜索包含该名称的可执行文件的目录。。

如果搜索成功,或者命令名称包含一个或多个斜杠,shell 将执行命名程序....

这与执行无关。这是因为您可以使用绝对或相对名称命名文件,并且可执行文件只是普通文件。

为什么危险?(.PATH)

考虑一个调用命令的脚本,例如cat foo,如果您在路径中有.,则可以在将执行的同一目录中创建一个命令cat来代替原始目录。

最新更新