为什么 ./a.out 可以工作,但 a.out 不工作?

为什么 ./a.out 可以工作,但 a.out 不工作?

a.out在我看来,即使是终端上的简单命令也包含有关当前目录中文件的完整信息。重申这一点./a.out似乎是多余的。

为什么我们需要指定文件在当前目录中才能执行它?

答案1

为什么我们需要指定文件在当前目录中才能执行它?

Shell 行为由 POSIX 标准化,并且出于安全原因,无法识别当前工作目录中的可执行文件。 a.out仅凭这一点还不足以说明全部情况。

具体来说,这被定义为Shell 命令语言的 POSIX 标准,命令搜索和执行部分在完成所有特定于 shell 的扩展和重定向以及内置查找之后:

否则,应使用 IEEE Std 1003.1-2001 的基本定义卷第 8 章环境变量中所述的 PATH 环境变量来搜索命令:

a.outshell 而言,它只是一串文本。根据文本字符串的排列方式,shell 需要删除重定向、变量替换和扩展;之后剩下的就是“命令”,它可能是也可能不是内置命令。在a.out任何常见的 shell 中都不是内置命令,所以这就是它./发挥作用的地方。

当然,你可以添加.到变量中PATH,这样它就可以工作了——然后你就可以调用它了a.out。但这是一个非常糟糕的做法,并且存在安全风险:请参阅将 . 添加到我的 PATH 中是否安全?为什么?

换句话说,不是的,这不是多余的。这只是 shell 的运作方式,并且出于技术原因而存在。


附注1: bashPATH根据手册,还接受零长度字段重击(1)

PATH 值中的零长度(空)目录名表示当前目录。空目录名可能显示为两个相邻的冒号,或者显示为首尾冒号。

附注2:使用的另一个好处./ 是避免与与本地可执行文件共享相同名称的系统实用程序混淆。虽然在这个特定问题中它专门讨论了a.out可执行文件名称(在编译 C 代码时自动分配),但如果编译代码并将输出命名为可执行文件test(即gcc -o test test.c生成可执行文件test并且您在 shell 中调用testnot 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,则可以调用可执行文件时不带前导./

相关内容