몇 가지 변수를 사용하여 find를 호출하려고 합니다. 지금까지 나는 이것을 가지고 있습니다 :
DIRECTORY="./ "
FILENAME=-regex" .*test.*"
find $DIRECTORY $FILENAME
좋은 결과. 파일 이름을 다음과 같이 변경하면:
FILENAME=-regex" .*"
디렉토리의 모든 파일을 나열하려면 다음 오류가 발생합니다.
find: paths must precede expression: ..
내가 뭘 잘못했나요?
답변1
변수의 내용 FILENAME
은
-regex .*test.*
따옴표는 변수 값의 일부가 아니라 셸 구문의 일부입니다. 쉘은 이것이 할당임을 발견하기 전에도 행을 구문 분석하고 따옴표를 해석합니다.
line을 실행하면 find $DIRECTORY $FILENAME
먼저 $FILENAME
해당 값으로 대체됩니다. 그런 다음 쉘은 변수 값에 대해 두 단계의 확장을 수행합니다. 즉, 변수에 공백이 포함된 별도의 단어(원하는 경우)로 분할하고 각 단어에 대해 와일드카드(즉, 와일드카드 확장)를 수행하여 다음과 같이 .*
확장됩니다. 현재 디렉터리에 있는 파일 점으로 시작하는 파일 이름 목록입니다.
.*test.*
패턴이 어떤 파일과도 일치하지 않아 패턴 자체로 확장되므로 첫 번째 코드 조각에는 문제가 없습니다 .
여러 단어를 저장해야 하는 경우 안정적인 솔루션은 문자열 변수 대신 배열 변수를 사용하는 것입니다.
DIRECTORY="./"
EXPRESSION=("-regex" ".*test.*")
find "$DIRECTORY" "${EXPRESSION[@]}"
또는 여러 디렉터리를 허용하려는 경우:
DIRECTORIES=("./")
EXPRESSION=("-regex" ".*test.*")
find "${DIRECTORIES[@]}" "${EXPRESSION[@]}"
"${EXPRESSION[@]}"
배열의 요소 목록으로 확장됩니다(별도의 단어로 표시됨).
"$foo"
"$(foo)"
값의 토큰화 및 와일드카드 지정을 원하지 않는 한 변수 대체 및 명령 대체 주위에는 항상 큰따옴표를 사용해야 합니다 .
여기서는 bash를 사용하고 있으므로 배열이 올바른 솔루션입니다. 배열이 없는 셸에는 여러 가지 가능성이 있습니다. 실제로 배열 변수인 위치 매개변수를 사용할 수 있지만 이는 다른 목적으로 사용하지 않는 경우에만 가능합니다.
set -- "./" # start with the directory
set -- "$@" -regex '.*' # add the expression
find "$@" # go
또 다른 접근 방식은 나중에 토큰화 및 와일드카드를 준비하기 위해 변수의 내용을 적절하게 인용하는 것입니다. ?*[
와일드카드 문자( ) 앞에 백슬래시를 사용하여 문자 그대로 해석되도록 할 수 있습니다 .
DIRECTORY=./
EXPRESSION='-regex .\*'
find "$DIRECTORY" $EXPRESSION
또 다른 접근 방식은 와일드카드를 비활성화하는 것입니다 set -f
. 이 find
줄을 실행하기 전에. set +f
나중에 필요할 경우 반드시 다시 켜십시오. 토큰화를 사용하므로 조건자 인수의 일부로 공백 문자를 전달할 수 없습니다 find
.
DIRECTORY=./
EXPRESSION='-regex .*'
set -f
find "$DIRECTORY" $EXPRESSION
또한 명령을 변수에 넣으려고 하는데 복잡한 경우가 항상 실패합니다! bash FAQ에서.
답변2
누구나
directory=.
match=(-regex '.*test.*')
find "$directory" "${match[@]}"
또는 (여기서 ","를 사용하여 강조):
directory=.
match='-regex,.*test.*'
IFS=,
set -f
find "$directory" $match
또는:
directory=.
match="-regex '.*test.*'"
eval 'find "$directory" '"$match"
답변3
변수에 대한 참조가 없습니다. 그러므로 쉘이 보는 것은
find ./ -regex .*
그리고 그것은 .*
.. ..