질문을 피하려면 find 명령을 사용하십시오.

질문을 피하려면 find 명령을 사용하십시오.

특정 하위 디렉터리와 파일을 제외하고 디렉터리의 모든 항목을 찾아야 합니다. 내 스크립트는 이것을 함수로 호출해야 합니다.

function findStuff() {
  # define exclusions
  ignore_dirs=("$1" "*foo*")                        # exclude base dir
  ignore_files=("one.txt" "two.txt" "*three*.txt")
  # build patterns for find command
  dir_pattern=""
  file_pattern=""
  for i in "${ignore_dirs[@]}"; do dir_pattern=$dir_pattern" ! -path \"$i\""; done
  for i in "${ignore_files[@]}"; do file_pattern=$file_pattern" ! -name \"$i\""; done
  # find
  find "$1 $dir_pattern $file_pattern"
  # now do other stuff with the results...
}

findStuff /some/base/dir

하지만 이로 인해 No such file or directory오류가 발생했습니다.

그래서 실제로 명령이 무엇인지 확인하고 echo find "$1 $dir_pattern $file_pattern"명령줄에 붙여넣어 보았는데 제대로 작동했습니다. 그런 다음 이를 스크립트에 붙여넣고 실행했는데 역시 작동했습니다!

그래서 회피 문제 때문에 실패한 것 같아요. 내가 뭘 잘못했나요?

답변1

find검색의 최상위 경로로 가져온 첫 번째 인수( -or 로 시작하는 첫 번째 인수( !or ) 까지)를 사용합니다 . 함수에서 호출할 때 문자열인 하나의 인수를 제공합니다 (변수는 확장됨). 경로를 찾을 수 없습니다.(find$1 $dir_pattern $file_pattern

에 제공하려는 매개변수 내에 리터럴 큰따옴표를 포함할 수도 있습니다 find. 큰따옴표가 하는 일은 쉘이 전역 패턴을 확장하고 IFS공백(또는 변수에 포함된 모든 것)으로 분할되는 것을 방지하는 것입니다. 그러나 예를 들어 사용하면 큰따옴표는 파일 이름과 비교하는 데 사용되는 패턴의 일부가 됩니다 ! -name \"thing\".find

배열을 사용하고 개별 매개변수를 올바르게 인용하십시오 find.

myfind () {
  local ignore_paths=( "$1" "*foo*" )
  local ignore_names=( "one.txt" "two.txt" "*three*.txt" )

  local path_args=()
  for string in "${ignore_paths[@]}"; do
      path_args+=( ! -path "$string" )
  done

  local name_args=()
  for string in "${ignore_names[@]}"; do
      name_args+=( ! -name "$string" )
  done

  find "$1" "${path_args[@]}" "${name_args[@]}"
}

path_argsand 위에 추가할 때마다 name_args목록에 !, -path또는 -name, 및 3개의 요소를 추가합니다 "$string". "${path_args[@]}"및가 확장 되면 "${name_args[@]}"(큰따옴표 참고) 요소가 개별적으로 인용됩니다.


동등한 구현이 다음에 적용됩니다 /bin/sh.

myfind () (
    topdir=$1

    set --

    # paths to ignore
    for string in "$topdir" "*foo*"; do
        set -- "$@" ! -path "$string"
    done

    # names to ignore
    for string in "one.txt" "two.txt" "*three*.txt"; do
        set -- "$@" ! -name "$string"
    done

    find "$topdir" "$@"
)

sh셸 에는 위치 인수 목록인 하나의 배열만 사용할 수 있으므로 그 안에 옵션을 수집합니다 $@. find분명히 bash단일 배열을 사용하도록 특정 솔루션을 작성할 수도 있으며 sh변형도 마찬가지로 작동합니다 bash.


마지막으로, 테스트 출력은 echo함수에 의해 실행된 명령을 정확하게 표현하지 않습니다.

생각해 보세요:

cat "my file name"

cat그것은 이라는 것에서 실행됩니다 my file name.

echo cat "my file name"

문자열을 출력합니다 cat my file name. 이는 쉘이 명령을 실행하기 전에 문자열 주위의 따옴표를 제거하기 때문입니다. 달리기저것명령을 내리면 cat찾아볼 것이다파일이 아니라 하나입니다.

명령을 셸에 복사하여 붙여넣으면 문자열 출력에 리터럴 큰따옴표 echo(이스케이프 처리)를 포함하기 때문에 제대로 작동하지만 이는 함수가 실행하는 실제 명령이 아닙니다.

관련 정보