我想在当前$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 制表符补全会执行的操作libreoffice
Tab。
如果您故意尝试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?.?"