![为什么 ./a.out 可以工作,但 a.out 不工作?](https://linux22.com/image/927759/%E4%B8%BA%E4%BB%80%E4%B9%88%20.%2Fa.out%20%E5%8F%AF%E4%BB%A5%E5%B7%A5%E4%BD%9C%EF%BC%8C%E4%BD%86%20a.out%20%E4%B8%8D%E5%B7%A5%E4%BD%9C%EF%BC%9F.png)
a.out
在我看来,即使是终端上的简单命令也包含有关当前目录中文件的完整信息。重申这一点./a.out
似乎是多余的。
为什么我们需要指定文件在当前目录中才能执行它?
答案1
为什么我们需要指定文件在当前目录中才能执行它?
Shell 行为由 POSIX 标准化,并且出于安全原因,无法识别当前工作目录中的可执行文件。 a.out
仅凭这一点还不足以说明全部情况。
具体来说,这被定义为Shell 命令语言的 POSIX 标准,命令搜索和执行部分在完成所有特定于 shell 的扩展和重定向以及内置查找之后:
否则,应使用 IEEE Std 1003.1-2001 的基本定义卷第 8 章环境变量中所述的 PATH 环境变量来搜索命令:
就a.out
shell 而言,它只是一串文本。根据文本字符串的排列方式,shell 需要删除重定向、变量替换和扩展;之后剩下的就是“命令”,它可能是也可能不是内置命令。在a.out
任何常见的 shell 中都不是内置命令,所以这就是它./
发挥作用的地方。
当然,你可以添加.
到变量中PATH
,这样它就可以工作了——然后你就可以调用它了a.out
。但这是一个非常糟糕的做法,并且存在安全风险:请参阅将 . 添加到我的 PATH 中是否安全?为什么?。
换句话说,不是的,这不是多余的。这只是 shell 的运作方式,并且出于技术原因而存在。
附注1: bash
PATH
根据手册,还接受零长度字段重击(1):
PATH 值中的零长度(空)目录名表示当前目录。空目录名可能显示为两个相邻的冒号,或者显示为首尾冒号。
附注2:使用的另一个好处./
是避免与与本地可执行文件共享相同名称的系统实用程序混淆。虽然在这个特定问题中它专门讨论了a.out
可执行文件名称(在编译 C 代码时自动分配),但如果编译代码并将输出命名为可执行文件test
(即gcc -o test test.c
生成可执行文件test
并且您在 shell 中调用test
not as command ),会发生什么?./test
shell 会/usr/bin/test
根据变量/usr/bin
中列出的内容查找PATH
并执行特定的二进制文件,而不是test
当前工作目录中指定的可执行文件。事实上,我之前已经回答过一个关于这种情况的问题:运行 shell 脚本时‘test’和‘test.sh’有什么区别?
答案2
这取决于你的 $PWD 是什么。
./a.out
告诉系统在当前目录中查找 a.out,因为你已提供了该文件的路径a.out
a.out
仅当 $PWD(您当前的工作目录)恰好位于 $PATH 或搜索二进制文件的目录中时才会起作用。
仅当您的当前目录在搜索字段中列出时才会进行搜索,这样可以减少错误并通过避免错误潜在地提高安全性。
答案3
从man bash
:
COMMAND EXECUTION
After a command has been split into words, if it results in a simple command
and an optional list of arguments, the following actions are taken.
If the command name contains no slashes, the shell attempts to locate it.
If there exists a shell function by that name, that function is invoked as
described above in FUNCTIONS. If the name does not match a function, the
shell searches for it in the list of shell builtins. If a match is found,
that builtin is invoked.
If the name is neither a shell function nor a builtin, and contains no
slashes, bash searches each element of the PATH for a directory containing
an executable file by that name.
换句话说,如果您调用可执行文件时不带前导./
,shell 将在 PATH 中搜索命令,但找不到该命令,因为当前目录不在您的 PATH 中。如果您将当前目录添加到 PATH,则可以调用可执行文件时不带前导./
。