类似路径的文件搜索

类似路径的文件搜索

基本上,我试图获得类似于命令搜索的内容$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/onesrc/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

相关内容