PATH 搜索是否包含符号链接?

use*_*908 9 shell symbolic-link which posix

POSIX shell 标准在这个站点上说

http://pubs.opengroup.org/onlinepubs/9699919799/

关于 shell 如何PATH用于查找可执行文件:

“应从头到尾搜索列表,将文件名应用于每个前缀,直到找到具有指定名称和适当执行权限的可执行文件。”

好吧,这不是在真正的 POSIX 实现中的工作方式:

man which 说:

“返回将在当前环境中执行的文件(或链接)的路径名,其参数在严格符合 POSIX 的 shell 中作为命令给出。它通过在 PATH 中搜索与名称匹配的可执行文件来实现参数。它不遵循符号链接。”

好,我们来看看这个情况:

$ pwd /home/mark

$ echo $PATH /home/mark/bin:...

$ ls -l bin/foobar
lrwxrwxrwx 1 mark mark 18 Dec 12 22:51 bin/foobar -> /home/mark/foobar1
$ touch foobar1
$ which foobar
$ chmod a+x foobar1
$ which foobar
/home/mark/bin/foobar
Run Code Online (Sandbox Code Playgroud)

好的,这里有一个PATH正确名称的符号链接,它被报告ls为可执行。

which 根本不看它,而只对它指向的东西感兴趣。

尽管事实上两者都man which明确表示它不遵循符号链接(实际上我们看到它没有,因为which foobar不打印foobar1),而且上面引用的 POSIX shell 文档从未提到PATH算法中的符号链接。

那么,which现有的 shell 是错误的,还是我不理解文档?

澄清:

我知道并且可以解释现有的行为。我的问题不是“这是如何工作的?”。我知道的。

我的问题是关于文档:在遵循我引用的文档时我的错误在哪里。还是文档有误?

动机:我为什么要关心?

嗯,我是一个实施者。不同的实施者有不同的要求。对我来说,要求是必须完全遵循当前 POSIX 标准的词(或者,更准确地说,它可能是最好的,因为标准本身有些错误)。就像上帝的话一样。

现在,标准措辞非常清楚——没有提到跟随符号链接,在许多其他地方,它在需要完成的地方被提到。所以在这种情况下,不要。

然而,我总是仔细检查如何dashbash行为,只是为了确保。现在当然,这里也有一个小问题,dash即使它标榜为 POSIX,也有很多符合 POSIX 的小错误。 bash,我还没有发现 POSIX 的任何错误,但是...... bash 实际上并不是 POSIX,它远不止于此。

所以你有它。这就是我关心的原因。

Joh*_*024 10

符号链接本身的权限无关紧要。如果你尝试过,你甚至无法改变它们。

重要的是底层文件的权限。

PATH 中的目录可以包含指向可执行文件的符号链接。事实上,PATH 中的许多可执行文件很可能是符号链接。例如,在类似 debian/ubuntu 的系统上:

$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Jan 23  2017 /bin/sh -> dash
Run Code Online (Sandbox Code Playgroud)

文档

来自man chmod

chmod 从不改变符号链接的权限;chmod 系统调用无法更改其权限。这不是问题,因为符号链接的权限从未使用过。 但是,对于命令行上列出的每个符号链接,chmod 会更改指向文件的权限。相比之下,chmod 会忽略递归目录遍历过程中遇到的符号链接。[强调。]

例子

shell 有一个测试 ,-x以确定文件是否可执行。让我们试试:

$ ls -l
total 0
lrwxrwxrwx 1 john1024 john1024 7 Dec 12 23:36 foo -> foobar1
-rw-rw---- 1 john1024 john1024 0 Dec 12 23:36 foobar1
$ [ -x foo ] && echo foo is executable
$ chmod +x foobar1
$ [ -x foo ] && echo foo is executable
foo is executable
Run Code Online (Sandbox Code Playgroud)

因此,就像您在 中发现which的那样,除非底层文件是可执行的,否则 shell 不会考虑软链接可执行文件。

如何运作

在 Debian 系统上,which是一个 shell 脚本。代码的相关部分是:

 case $PROGRAM in
  */*)
   if [ -f "$PROGRAM" ] && [ -x "$PROGRAM" ]; then
    puts "$PROGRAM"
    RET=0
   fi
   ;;
  *)
   for ELEMENT in $PATH; do
    if [ -z "$ELEMENT" ]; then
     ELEMENT=.
    fi
    if [ -f "$ELEMENT/$PROGRAM" ] && [ -x "$ELEMENT/$PROGRAM" ]; then
     puts "$ELEMENT/$PROGRAM"
     RET=0
     [ "$ALLMATCHES" -eq 1 ] || break
    fi
   done
   ;;
 esac
Run Code Online (Sandbox Code Playgroud)

如您所见,它使用-x测试来确定文件是否可执行。

POSIX 指定-x测试如下:

-x pathname
如果 pathname 解析为文件的现有目录条目,则该文件将被授予执行文件(或搜索它,如果它是目录)的权限,则为真,如文件读取、写入和创建中所定义。如果 pathname 无法解析,或者 pathname 解析为文件的现有目录条目,则不会授予执行(或搜索)该文件的权限,则为 False。[强调。]

因此,POSIX 检查路径名解析为什么。换句话说,它接受符号链接。

POSIX 执行函数

POSIX exec函数如下符号链接。POSIX 规范详细说明了如果符号链接是圆形或太深,它可能会报告的错误条件,例如:

[ELOOP]
在解析路径或文件参数期间遇到的符号链接中存在循环。

[ELOOP]
在解析路径或文件参数期间遇到超过 {SYMLOOP_MAX} 个符号链接。
[ENAMETOOLONG]
由于在解析路径参数时遇到符号链接,替换的路径名字符串的长度超过了 {PATH_MAX}。

  • @user322908 [POSIX `exec` 函数](http://pubs.opengroup.org/onlinepubs/009604599/functions/exec.html) 遵循符号链接。这似乎很清楚,符号链接文件在 POSIX 下可以是可执行文件。 (4认同)
  • 我还检查了 [Ubuntu 17.10 `man which`](http://manpages.ubuntu.com/manpages/artful/en/man1/which.1.html),上面写着“它没有规范化路径名”。这并不意味着它不遵循链接。正如您所观察到的那样,这仅意味着它不会“规范化”名称。 (2认同)