@Kusalananda 는 이미 기본 문제와 그 해결 방법에 대해 설명 했으며 @glenn jackmann 이 링크 한 Bash FAQ 항목 에도 유용한 정보가 많이 있습니다. 다음은 이러한 리소스를 기반으로 내 문제가 어떻게 발생하는지에 대한 자세한 설명입니다.
작은 인수를 사용하여 각 인수를 별도의 줄에 인쇄하여 사물을 설명합니다 ( argtest.bash
).
#!/bin/bash
for var in "$@"
do
echo "$var"
done
"수동으로"옵션 전달 :
$ ./argtest.bash -rnv --exclude='.*'
-rnv
--exclude=.*
예상대로, 부분 -rnv
과 --exclude='.*'
따옴표가없는 공백으로 구분되므로 두 개의 인수로 나뉩니다 (이를 단어 분리 라고 함 ).
또한 따옴표 주위에주의 .*
제거 된 : 작은 따옴표는 콘텐츠를 전달하는 쉘에게 특별한 해석없이 , 하지만 따옴표는 자신이 명령에 전달되지 않습니다 .
옵션을 변수에 문자열로 저장하면 (배열 사용과 반대) 따옴표 는 제거되지 않습니다 .
$ OPTS="--exclude='.*'"
$ ./argtest.bash $OPTS
--exclude='.*'
이것은 두 가지 이유 때문입니다. 정의 할 때 사용되는 큰 따옴표는 작은 따옴표의 $OPTS
특수 처리를 방지하므로 후자는 값의 일부입니다.
$ echo $OPTS
--exclude='.*'
이제 $OPTS
명령의 인수로 사용하면 매개 변수 확장 전에 따옴표가 처리 되므로 따옴표가 $OPTS
너무 늦게 발생합니다.
이것은 (원래의 문제에서) rsync
패턴 '.*'
대신 제외 패턴 (따옴표 포함! )을 사용 한다는 것을 의미 합니다. .*
이름이 작은 따옴표로 시작하고 점으로 끝나고 작은 따옴표로 끝나는 파일은 제외합니다. 분명히 그것은 의도 된 것이 아닙니다.
해결 방법은 다음을 정의 할 때 큰 따옴표를 생략하는 것입니다 $OPTS
.
$ OPTS2=--exclude='.*'
$ ./argtest.bash $OPTS2
--exclude=.*
그러나 보다 복잡한 경우에는 미묘한 차이로 인해 변수 할당 을 항상 인용 하는 것이 좋습니다 .
@ Kusalananda가 지적했듯이 인용하지 않는 .*
것도 효과가 있었을 것입니다. 패턴 확장 을 막기 위해 따옴표를 추가 했지만 이 특별한 경우에는 꼭 필요하지 않았습니다 .
$ ./argtest.bash --exclude=.*
--exclude=.*
Bash 는 패턴 확장을 수행하지만 패턴 --exclude=.*
이 파일과 일치하지 않으므로 패턴이 명령으로 전달됩니다. 비교:
$ touch some_file
$ ./argtest.bash some_*
some_file
$ ./argtest.bash does_not_exit_*
does_not_exit_*
그러나 어떤 이유로 든 파일이 일치 --exclude=.*
하면 패턴이 확장 되기 때문에 패턴을 인용하지 않는 것은 위험합니다 .
$ touch -- --exclude=.special-filenames-happen
$ ./argtest.bash --exclude=.*
--exclude=.special-filenames-happen
마지막으로, 배열을 사용하면 내 인용 문제가 발생하지 않는 이유를 살펴 보겠습니다 (배열을 사용하여 명령 인수를 저장하는 다른 이점 외에도).
배열을 정의 할 때 단어 분할 및 따옴표 처리가 예상대로 수행됩니다.
$ ARRAY_OPTS=( -rnv --exclude='.*' )
$ echo length of the array: "${#ARRAY_OPTS[@]}"
length of the array: 2
$ echo first element: "${ARRAY_OPTS[0]}"
first element: -rnv
$ echo second element: "${ARRAY_OPTS[1]}"
second element: --exclude=.*
옵션을 명령에 전달할 때 우리는 구문을 사용 "${ARRAY[@]}"
하여 배열의 각 요소를 별도의 단어로 확장합니다.
$ ./argtest.bash "${ARRAY_OPTS[@]}"
-rnv
--exclude=.*