如何在 PATH 上可靠地找到程序的完整路径?

Seb*_*der 12 shell path

我需要PATH使用 shell 脚本找到给定程序的路径。路径必须是程序的实际完整路径,稍后可以将其传递给exec*不搜索PATH自身的函数之一,例如execv.

有一些程序,例如kill,它们可以同时作为实际程序和内置 shell 使用。如果是这种情况,我需要实际程序的完整路径。

有几个实用程序可以PATH第 2.9.1.1 节,POSIX 标准的命令搜索和执行中指定的程序上找到程序。

which,它不是任何标准的一部分。它可以是某些系统上的常规程序,而某些 shell 则提供它是内置程序。它似乎在大多数系统和 shell 上都可用,但是具有内置版本的 shell 也只返回内置版本的名称而不是可执行文件的路径。此外,它没有以任何方式标准化,可能会返回任何输出并采用不同的选项。

bash# which kill
/usr/bin/kill
dash# which kill
/usr/bin/kill
fish# which kill
/usr/bin/kill
mksh# which kill
/usr/bin/kill
tcsh# which kill
kill: shell built-in command.
zsh# which kill
kill: shell built-in command
Run Code Online (Sandbox Code Playgroud)

whence,它是几个 shell 的内置函数。但在许多外壳上不可用。它也将返回内置程序的名称而不是程序路径。-p可以将A传递给 wherece 以更改此行为。

bash# whence kill
bash: whence: command not found
dash# whence kill
dash: 1: whence: not found
fish# whence kill
fish: Unknown command 'whence'
mksh# whence kill
kill
mksh# whence -p kill
/usr/bin/kill
tcsh# whence kill
whence: Command not found.
zsh# whence kill
kill
zsh# whence -p kill
/usr/bin/kill
Run Code Online (Sandbox Code Playgroud)

commandPOSIX:2008 指定内置函数。不幸的是,它还搜索常规命令和内置程序,并将返回内置程序的名称,而不是由同名内置程序遮蔽的程序路径。一些旧的 shell 还没有实现它。

bash# command -v kill
kill
dash# command -v kill
kill
fish# command -v kill
/usr/bin/kill
mksh# command -v kill
kill
tcsh# command -v kill
command: Command not found.
zsh# command -v kill
kill
Run Code Online (Sandbox Code Playgroud)

Zac*_*ady 11

自己去寻找就行了。

export IFS=":"
[ -z "${1}" ] && exit 1
for dir in $PATH
do if [ -x "${dir}/${1}" ]
   then echo "${dir}/${1}"
        exit 0
   fi
done
echo ${1} not found
exit 1
Run Code Online (Sandbox Code Playgroud)

bash, dash, ksh, mksh, 中测试zsh

更新

以上对于独立脚本来说很好,但是如果您打算将其嵌入到更大的脚本中,您可能需要使用更类似于以下内容的内容。

function find_path() {
   IFS_SAVE="${IFS}"
   export IFS=":"
   [ -z "${1}" ] && return 1
   for dir in $PATH
   do if [ -x "${dir}/${1}" ]
      then echo "${dir}/${1}"
           export IFS="${IFS_SAVE}"
           return 0
      fi
   done
   export IFS="${IFS_SAVE}"
   echo ${1} not found
   return 1
}
Run Code Online (Sandbox Code Playgroud)

这是为了IFS在找到匹配项后恢复,也将exit's 与return's交换

  • 如果您将它集成到一个更大的 shell 脚本中(而不是将它自己制作成一个脚本,这可能是预期的),您可能希望之后恢复 IFS 的旧值 - 否则可能会对脚本的其余部分... (3认同)