基本上,我试图获得类似于命令搜索的内容$PATH
,但具有不同的目录列表,并且我正在搜索的文件不可执行。
目录列表是固定的(我可以将其打包到与 PATH 格式相同的变量中,或者其他什么),并且我不想下降到子目录中。我依稀记得 bashcomplete
有一个选项,但我通读了该部分,但没有发现它。我很接近吗?
也许是这样的(假设文件位于~/lib
):
> filepath -p ".:/etc:$HOME/lib:$HOME/bin" foo
/home/alexis/lib/foo
换句话说,我正在寻找类似which
或 的东西which -a
,无论什么都更容易,但它不应该仅限于可执行文件(并且它不应该只搜索$PATH
,但我可以解决这个问题;-))。
答案1
find
已经支持多个搜索路径
find . /etc ~/lib ~/bin -maxdepth 1 -name '*foo*'
或者使用fd
这比 find 更快、功能更丰富、更漂亮
fd --max-depth=1 foo . /etc ~/lib ~/bin
另一种简单的方法,但可能不适用于带有空格或换行符的文件:
SearchPaths=(/etc ~/lib ~/bin)
shopt -s nullglob
eval printf "%s " "${SearchPaths[@]/%/*foo*}"
我相信我见过一种使用 bash 数组进行直接文件扩展的更简单的方法,但我现在不记得了
答案2
您可以使用 bash 函数作为 GNU 的包装器find
:
filepath () {
local fp_path=${FP_PATH:-".:/etc:$HOME/lib:$HOME/bin"} fpath fquit=-quit
local usage="usage: filepath [-a] [-p path[:path...]] expr"
OPTIND=1
while getopts :ap: opt; do
case $opt in
a) fquit=
;;
p) fp_path=$OPTARG
;;
*) echo "$usage" >&2
return 1
esac
done
shift $((OPTIND-1))
if [ -z "$1" ]; then
echo "$usage" >&2
return 1
fi
IFS=: read -r -a fpath <<<"$fp_path"
find "${fpath[@]}" -maxdepth 1 \( -type f -o -type l \) -name "$1" -print $fquit 2>/dev/null
}
默认搜索路径定义在函数的第一行,用作:
分隔符。它可以被环境变量FP_PATH
或选项覆盖-p
。除非使用
find
选项,否则打印第一个结果后退出。-a
搜索仅限于常规文件和符号链接,根据需要调整选项。
例子:
$ mkdir -p ~/bin /tmp/etc
$ touch ~/bin/foo /tmp/foo /tmp/etc/foo
$ filepath
usage: filepath [-a] [-p path[:path...]] expr
$ filepath -a -p /tmp:/tmp/etc 'fo*'
/tmp/foo
/tmp/etc/foo
$ filepath -p /tmp:/tmp/etc 'fo*'
/tmp/foo
$ FP_PATH=/tmp filepath foo
/tmp/foo
$ filepath foo
/home/freddy/bin/foo
答案3
如果您愿意将目录列表存储在数组 ( bash
) 中,您可以使用如下代码:
# Maybe in ~/.bashrc
filefindlist=(. /etc "$HOME/lib" "$HOME/bin" src/*)
filefind() {
local ff
for ff in "${filefindlist[@]}"
do
if [ -d "$ff" ] && [ -f "$ff/$1" ]
then
printf '%s\n' "$ff/$1"
return 0
fi
done
return 1
}
用法
filefind program.c
filefindlist
请注意,任何变量和 shell 全局变量(通配符)都将在定义数组时进行评估。因此,如果您有src/one
并稍后创建src/two
,那么src/*
只会扩展到src/one
.不过,下次定义数组时,它将包含src/one
和src/two
。
如果您想准确实施问题中的建议,则可以使用以下方法:
filefind() {
local fl="$FILEFINDLIST" fp ff
[ "$1" = '-p' ] && fl="$2" && shift 2 # Override default search list
readarray -d: -t fp <<<"$fl" # Convert to array
for ff in "${fp[@]}"
do
if [ -d "$ff" ] && [ -f "$ff/$1" ]
then
printf '%s\n' "$ff/$1"
return 0 # Only print first match
fi
done
return 1
}
用法
FILEFINDLIST='.:$HOME/lib:$HOME/bin'
filefind -p ".:/etc:$HOME/lib:$HOME/bin" program.c
filefind program.c
答案4
和zsh
:
filepath() print -rC1 -- ${(s[:])^1}/$^@[2,-1](N)
然后:
$ filepath .:/etc:$HOME/lib:$HOME/bin ls issue python
/etc/issue
/home/chazelas/lib/python
/home/chazelas/bin/ls