sh 不考虑 $PATH

Joh*_*n V 2 shell path

这有效

sh /opt/gap-4.11.1/bin/gap.sh
Run Code Online (Sandbox Code Playgroud)

这不起作用

sh gap.sh
Run Code Online (Sandbox Code Playgroud)

并返回错误信息

sh: 0: Can't open gap.sh
Run Code Online (Sandbox Code Playgroud)

但所需的目录位于 中$PATH,如所确认的echo $PATH

/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/gap-4.11.1/bin
Run Code Online (Sandbox Code Playgroud)

怎么了?

Sté*_*las 5

虽然 POSIX 允许sh实现在当前工作目录中找不到何时查找file,因为这就是(规范所基于的子集)所做的,但它并不需要它,而且现在大多数实现都不需要它(甚至不)因为这是不可取的。$PATHsh filefilekshshshmksh

事实上 POSIX 允许这样做并且某些实现确实会导致相反的问题:

sh -- "$file"
Run Code Online (Sandbox Code Playgroud)

POSIX 不保证解释路径存储在 中的文件$file,因此您必须执行以下操作:

case $file in
  ('') echo >&2 error;;
  (*/*) sh -- "$file";;
  (*) sh "./$file";;
esac
Run Code Online (Sandbox Code Playgroud)

可移植地解决它。

这也是为什么你看到人们使用:

sh ./file
Run Code Online (Sandbox Code Playgroud)

当他们想要确保它是file在当前目录中被解释并且不冒解释 if$PATH碰巧file丢失的一些完全不相关的脚本的风险时,就像您在当前工作目录而不是在当前工作目录中./ls运行命令一样ls$PATH

该实用程序也存在类似的问题,.该实用程序$PATH$file不包含/. 虽然 POSIX 不允许在未处于$PATHsh 模式时在 bash 或 zsh 中找到该文件,但不允许回退到解释当前目录中的文件。csh' 相当于.source不进行$PATH查找。在 中zshsource退回到$PATH查找。在 中bashsource行为类似于.

在这里,由于您的脚本位于 中$PATH,并且假设您具有它的执行权限,因此您只需输入:

gap.sh
Run Code Online (Sandbox Code Playgroud)

为了gap.sh在 中查找$PATH。如果脚本没有 shebang,则应由sh符合 POSIX 的解释器进行解释。

如果你有读权限但没有执行权限,你可以这样做:

sh -c '. gap.sh' sh arguments for gap.sh
Run Code Online (Sandbox Code Playgroud)

如上所示,它将进行$PATH查找。

作为历史记录,on 过去ksh file常常首先ksh进行$PATH查找。这是支持 setuid 脚本的系统上的一个安全漏洞,您可以这样做:

ln -s /path/to/some/setuid/ksh/script /tmp/file
echo sh > ~/bin/file
PATH=$PATH:~/bin
cd /tmp
Run Code Online (Sandbox Code Playgroud)

并且exec("file", ...)使用 shebang 调用 which#! /bin/ksh -将会 /bin/ksh - file以 setuid 用户身份运行,并且ksh最终会进行解释~/bin/file而不是/tmp/file,因此如果脚本是 setuid root,您将获得 root shell。