인수에서 find 명령 작성

인수에서 find 명령 작성

종종 파일을 찾아야 하는데 다음과 같이 파일 이름이 무엇인지 잘 모르겠습니다.

$ find -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'

좀 지루해요. 다음과 같이 사용하기 쉬운 별칭을 만들고 싶습니다.

$ findany foo bar blah

내 시도는 다음과 같습니다.

findany() {
    args=("-iname" "'*$1*'")
    shift

    while [ $# -gt 0 ]; do
        args+=("-o" "-iname" "'*$1*'")
        shift
    done

    find ${args[@]}
}

문제는 파일이 바로 거기에 있어도 결과가 전혀 생성되지 않는다는 것입니다.

$ ls
bar.txt  blah.txt  foo.txt

$ findany foo bar blah
# nothing

echo명령 앞에 추가 하면 올바르게 보입니다.

$ findany foo bar blah                     
find -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'

위의 출력을 복사하여 실행하면 정상적으로 작동합니다.

$ find -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'
./bar.txt
./foo.txt
./blah.txt

매개변수 분할이나 인용과 관련이 있는 것 같은데 어떻게 디버깅해야 할지 모르겠습니다.

저는 주로 zsh를 사용하는데, bash에서도 동일한 동작을 확인했습니다.

답변1

당신은 매우 가깝습니다! 그러나 어떤 이유로 파일 이름 자체에 작은따옴표를 포함하면 일치하지 않습니다.

또한 "${args[@]}"이것이 제대로 작동하려면 견적을 작성해야 합니다. 그렇지 않으면 토큰화의 영향을 받게 되며 모든 glob은 find표시되기 전에 셸에서 확장됩니다.

다음을 시도해 보십시오(특히 의 경우 bash).

findany() {
    local args=('-iname' "*$1*")
    shift

    while [ "$#" -gt 0 ]; do
        args+=('-o' '-iname' "*$1*")
        shift
    done

    find . "${args[@]}"
}

답변2

zsh를 사용하면 다음을 사용할 수 있습니다.

set -o extendedglob # usually in your ~/.zshrc, here used for (#i) for
                    # case insensitive matching
print -rC1 -- **/*(#i)(foo|bar|blah)*(ND)

배열에서 패턴을 구축하려면 j[|]매개변수 확장 플래그를 사용하여 배열의 요소를 연결하고 |매개변수 확장 플래그와 결합하여 전역 패턴 연산자로 처리 ~되거나 매개변수 확장 연산자를 사용하여 연결을 수행할 수 있습니다. 문자 문자열 내의 와일드카드 문자(배열 요소 내에 있는 경우에도)는 패턴으로 간주됩니다.|~

findany1() print -rC1 -- **/*(#i)(${(~j[|])argv})*(ND)

또는:

findany2() print -rC1 -- **/*(#i)(${(j[|])~argv})*(ND)

예를 들어 이름 findany1 '??'에 2자 이상의 문자가 포함된 파일이 검색됩니다. 을 포함하는 이름이 필요 하거나 찾습니다 .??findany2findany2 '\?\?'findany2 '[?][?]'??findany2

와 동일한 구별을 하려면 find다음과 같습니다.

findany2() (
  for arg do
    argv+=( -o -iname "$arg" )
    shift
  done
  shift
  find . "$@"
)
findany1() (
  set -o extendedglob
  for arg do
    argv+=( -o -iname "${arg//(#m)[][\\?*]/\\$MATCH}" )
    shift
  done
  shift
  find . "$@"
)

find( ?, 및 ) 로 *인식되는 와일드카드 문자를 ( / 는 지원되는 유일한 참조 연산자입니다)로 이스케이프합니다.[...]\\findfnmatch()

답변3

$ find -iname '*foo*' -o -iname '*bar*' -o -iname '*blah*'

이것은 문제를 해결하는 한 가지 방법이지만 솔직히 다음과 같은 결과를 낳습니다.

shopt -s globstar  ## enable recursive globbing operator **
shopt -s extglob   ## enable (|) pattern lists
shopt -s nocasematch  ## take a guess!

echo **/*@(foo|bar|blah)*

(그러나 그렇게 하는 데는 도움이 필요하지 않습니다 find).

쉘 스크립트를 빠르게 작성할 수 있습니다.

#! /bin/bash -
shopt -s globstar  ## enable recursive globbing operator **
shopt -s extglob   ## enable (|) pattern lists
shopt -s nullglob  ## don't error if nothing matches
shopt -s nocasematch  ## take a guess!

IFS='|' # "$*" joins with the first character of IFS
pattern="**/*@(${*})*"

IFS= # do globbing but not splitting upon unquoted expansion:
matches=( $pattern )

for element in "${matches[@]}"; do
  printf '%s\n' "${element}"
done

함수로 만들고 싶다면 pattern=…함수 done선언에 넣으세요.

관련 정보