내 변수에 따옴표로 묶인 glob이 포함되어 있고 큰따옴표를 사용하지 않고 확장한 경우 glob이 사라지는 이유는 무엇입니까?

내 변수에 따옴표로 묶인 glob이 포함되어 있고 큰따옴표를 사용하지 않고 확장한 경우 glob이 사라지는 이유는 무엇입니까?

인용되지 않은 문자열 확장을 사용하여 tar에 두 개의 인수를 전달하려고 합니다. 첫 번째 인수는 명령줄 플래그 --exclude이고 두 번째 인수는 *문자를 포함합니다. 조기 와일드카드를 피하기 위해 다음을 인용해 보았습니다 *.

shopt -s nullglob
x="--exclude '*'"
echo tar $x

놀랍게도 '*'완전히 사라졌습니다! 출력은 다음과 같습니다.

tar --exclude

POSIX 셸에서 Bash로 전환하고 배열을 사용하면 이 문제를 피할 수 있다는 것을 알고 있습니다. 하지만 나는 여전히 알고 싶습니다. POSIX 셸 조각에 도대체 무슨 일이 벌어지고 있는 걸까요? 참조된 glob을 삭제하는 이유는 무엇입니까? 인용된 부분을 그대로 유지하거나, 쭉 확장해서 글로벌하게 확장할 것이라고 생각했을 것입니다. 하지만 둘 다 그렇지 않습니다.

답변1

첫째, 이미 사용하고 있거나 bash적어도 POSIX가 아닌 옵션 중 일부를 사용하고 있습니다. ( POSIX 도 마찬가지 shopt입니다 nullglob.)

이제 무슨 일이 일어나고 있는지 설명하겠습니다.

x="--exclude '*'"
echo tar $x

이 변수는 $x공백을 토큰화하고 결과 부분을 글로빙에 사용합니다. --exclude와일드카드가 없으며 그대로 유지됩니다. '*'일치하는 항목이 없습니다(파일 이름이 문자 그대로 작은따옴표로 시작하고 끝나지 않는 한). 와일드카드가 포함되어 있고 nullglob삭제하도록 설정했기 때문입니다. 밝혀지다

tar --exclude

이미 사용하고 계시기 때문에 bash한번 사용해보시는 것도 좋을 것 같습니다.

x=('--exclude' '*')
echo tar "${x[@]}"

POSIX 솔루션을 원한다면 제가 제공할 수 있는 최선의 방법은 기본 매개변수 목록을 재사용하는 것입니다.

set -- '--exclude' '*'
echo tar "$@"

답변2

이와 같은 코너 케이스의 경우 쉘 확장 순서배쉬 문서예상치 못한 동작이 발생하는 경우가 많습니다. Posix는 거의 동일한 동작을 가지고 있지만 덜 명확하게 설명되어 있습니다.

일어나는 일은 다음과 같습니다.

nullglob을 nullglob로 변환했으므로 실패한 glob은 비어 있습니다.

다음으로 리터럴 별표와 작은따옴표가 포함된 변수를 설정합니다.

그런 다음 변수의 내용을 에코하면 다음이 발생합니다.

  1. 변수가 텍스트로 확장됩니다. 텍스트에는'*'
  2. '*'작은따옴표로 인해 문자열 리터럴이 될 것이라고 생각하더라도 기존 파일 이름은 여전히 ​​대체됩니다. Nullglob은 이를 빈 문자열로 변환합니다.
  3. 명령이 실행됩니다

관련 정보