在 $PATH 中执行与通配符匹配的命令

在 $PATH 中执行与通配符匹配的命令

我想在当前$PATH匹配此通配符的情况下查找并执行命令libreoffice?.?(例如libreoffice4.0,,libreoffice4.3等)

编辑:如果找到多个匹配项,您可以随机选择一个。

我更喜欢符合 POSIX 标准的解决方案。

答案1

设置IFS为以分割冒号:的值。PATH如果您find-quit操作和-maxdepth主要(例如 FreeBSD、OSX、GNU),您知道该命令将存在并且您不关心命令的返回代码,您可以使用以下一行:

pattern='libreoffice?.?'
IFS=:; find $PATH -maxdepth 1 -type f -name "$pattern" -exec {} \; -quit; unset IFS

这并没有提供一种简单的方法来报告是否找到该命令。此外,为了更加稳健,请关闭通配符,以防 的值PATH包含通配符。另外,可以有一个空组件来PATH表示当前目录(但我的建议是使用.它)。下面的代码可以解决所有这些复杂问题。

pattern='libreoffice?.?'
case $PATH in
  :*) directories=.$PATH;;
  *::*) directories=${PATH%%::*}:.:${PATH#*::};;
  *:) directories=$PATH.;;
  *) directories=$PATH;;
esac
set -f; IFS=:
cmd=
for d in $directories; do
  set +f
  for x in "$d"/$pattern; do
    if [ -x "$x" ] && ! [ -d "$x" ]; then
      cmd=$x
      break
    fi
  done
  if [ -n "$cmd" ]; then break; fi
done
set +f; unset IFS
if [ -z "$cmd" ]; then
  echo 1>&2 "$pattern: not found in PATH"
  exit 127
else
  exec "$cmd"
fi

如果您碰巧使用 zsh(而不是普通的 sh、bash、ksh 等),那么制定一个强大的解决方案会简单得多。

pattern='libreoffice?.?'
matches=($^path/$~pattern(N.*[1]))
if ((!#matches)); then
  $matches[1]
else
  echo 1>&2 "$pattern: not found in PATH"
  exit 127
fi

答案2

这是一个更简单的替代方案:

$(compgen -c libreoffice)

它假定 bash,并且假定只libreoffice*安装了一个。

如果您输入 ,它会模拟 bash 制表符补全会执行的操作libreofficeTab

如果您故意尝试libreoffice在没有版本号的情况下进行排除,并且想要处理多个版本的存在,请尝试:

run_libreoffice() {
    compgen -c libreoffice |
        while read -r exe; do
            case "$exe" in libreoffice?.?)
                "$exe" "$@"
                return
                ;;
            esac
        done
}
run_libreoffice "$@"

case语句使其仅匹配libreoffice?.?,并且我们循环结果,仅运行第一个。

答案3

zsh

$commands[(i)libreoffice?.?]

在 中zsh$commands是一个特殊的关联数组,其键是命令名称,值为它们的路径。

i上面是一个数组下标标志告诉zsh将模式与数组键进行匹配并返回第一个匹配的键。

但关联数组的元素没有任何特定的顺序,因此第一的匹配的键不一定是第一个出现在 中的键$PATH。如果你想要libreoffice最大版本号,你可以这样做:

${${(nO)${commands[(I)libreoffice?.?]}}[1]}

下标标志I扩展为全部匹配的键。我们使用n(数字排序)和O(逆序)参数扩展标志将该列表从最大到最小版本号排序,然后[1]选择第一个。

也可以看看:

whence -m 'libreoffice?.?'

找到相应命令的路径。

答案4

您可以使用“查找”命令,如下所示

find ./ -name "libreoffice?.?"

相关内容