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 标准的词(或者,更准确地说,它可能是最好的,因为标准本身有些错误)。就像上帝的话一样。
现在,标准措辞非常清楚——没有提到跟随符号链接,在许多其他地方,它在需要完成的地方被提到。所以在这种情况下,不要。
然而,我总是仔细检查如何dash和bash行为,只是为了确保。现在当然,这里也有一个小问题,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 exec函数如下符号链接。POSIX 规范详细说明了如果符号链接是圆形或太深,它可能会报告的错误条件,例如:
[ELOOP]
在解析路径或文件参数期间遇到的符号链接中存在循环。
[ELOOP]
在解析路径或文件参数期间遇到超过 {SYMLOOP_MAX} 个符号链接。
[ENAMETOOLONG]
由于在解析路径参数时遇到符号链接,替换的路径名字符串的长度超过了 {PATH_MAX}。