如果我有一个以冒号分隔的路径列表,很像 $PATH,但不一定是 $PATH。
我想在该列表中搜索特定文件名。但是,我只想要第一个匹配的路径。
我考虑过以下Linux命令:
which
:仅适用于二进制文件,并且仅适用于 $PATH 变量whereis
:适用于特定类型的文件,并且仅适用于 $PATH 变量find
:不支持冒号分隔的路径列表,并返回多个结果
以下是我尝试过的一些方法:
我尝试使用
whereis
以下策略env WHEREIS="`which whereis`" PATH="$MY_PATH_LIST" $WHEREIS "$TARGET_FILE"
这几乎可以正常工作。但是,它似乎不会返回任意文件类型的结果。它还会返回多个结果,并且格式很别扭。
which
我可以env WHICH="`which which`" PATH="$MY_PATH_LIST" $WHICH "$MY_TARGET_FILE"
如果有一个命令行选项强制它允许不可执行文件。
然后我尝试用 来解决问题
find
。首先,我使用正则表达式来扩展路径列表(我用空格替换冒号)。然后我调用 find,它工作正常。但是,它会搜索所有路径。我似乎找不到一种方法来告诉它在找到好结果时尽早停止搜索。我确实让它工作了
find ${MY_PATH_LIST//[:]/ } -name "$MY_TARGET_FILE" | head -n 1
但它需要很长时间才能完成,因为
find
仍在进行详尽的搜索。我需要它执行得更快(第一个结果时退出),因为它将使用不同的参数运行多次。
有人有更好的解决方案可以建议吗?
请注意,如果一切都失败了,我可以编写一个非 bash 解决方案。现在写我希望使用现有工具找到一个简单的解决方案。
答案1
您可以使用一个脚本来简单测试(-e
)文件是否存在,并在找到第一个文件时停止:
#!/bin/bash
[[ $# -gt 0 ]] || { echo "Usage: $0 <filename> [pathspec]" >&2 ; exit 1 ; }
if [[ $# -gt 1 ]] ; then
P="$2"
else
P="$PATH"
fi
IFS=:
for DIR in $P ; do
if [[ -e "$DIR/$1" ]] ; then
echo "$DIR/$1"
exit 0
fi
done
例子:
$ ./search.sh
Usage: ./search.sh <filename> [pathspec]
$ ./search.sh ls
/Users/danielbeck/bin/ls
$ ./search.sh pwd
/bin/pwd
$ ./search.sh ls /bin
/bin/ls
$ ./search.sh ls /usr/bin:/bin
/bin/ls
答案2
使用 head 获取 find 命令的第一个结果。
find `echo colon:separated:directories | sed 's/:/ /g'` -name filename | head -n1
或者在函数中:
$ function findin { find `echo $1 | sed 's/:/ /g'` -name $2 | head -n1; }
$ findin this:that:other filename
答案3
您可以使用该which
命令,并PATH
仅为该命令的范围设置变量。例如
PATH="/path1:/path2" which "file1.txt"
如果存在则返回/path1/file1.txt
,否则返回/path2/file1.txt
。
答案4
以下是如何修复使用 的尝试,find
以避免进入子目录并在找到一个文件时停止。诀窍是使用-maxdepth
和-quit
来处理您遇到的问题。如果您还想忽略与搜索名称匹配的子目录,您可以-type f
在 之前插入-print
。
find ${MY_PATH_LIST//[:]/ } -maxdepth 1 -name "$MY_TARGET_FILE" -print -quit