경로형 파일 검색

경로형 파일 검색

기본적으로 search 명령과 비슷한 것을 얻으려고 하는데 $PATH디렉터리 목록이 다르고 검색 중인 파일이 실행 가능하지 않습니다.

디렉토리 목록은 고정되어 있으며(PATH와 같은 형식의 변수로 압축할 수 있음) 하위 디렉토리로 드롭다운하고 싶지 않습니다. bash에 complete옵션이 있다는 것을 어렴풋이 기억하지만 해당 섹션을 끝까지 읽었지만 찾지 못했습니다. 나는 가까운가?

어쩌면 다음과 같을 수도 있습니다(파일이 있다고 가정 ~/lib).

> filepath -p ".:/etc:$HOME/lib:$HOME/bin" foo
/home/alexis/lib/foo

which즉, or 와 같은 것을 찾고 있지만 which -a실행 파일에만 국한되어서는 안 됩니다. 실행 파일만 검색하면 안 되지만 $PATH문제를 해결할 수 있습니다 ;-).

답변1

find이미 여러 검색 경로를 지원합니다.

find . /etc ~/lib ~/bin -maxdepth 1 -name '*foo*'

또는 사용fdfind보다 더 빠르고 기능이 풍부하며 더 아름답습니다.

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배열을 정의할 때 모든 변수와 쉘 전역 변수(와일드카드)가 평가됩니다. 따라서 src/one나중에 배열을 생성 하면 으로만 확장됩니다 src/two. 그러나 다음에 배열을 정의할 때는 및 가 포함됩니다 .src/*src/onesrc/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

관련 정보