Bash: $() 명령 대체에서 큰따옴표를 이스케이프 처리함

Bash: $() 명령 대체에서 큰따옴표를 이스케이프 처리함

일부 매개변수가 변수에서 나온 경우 명령 대체가 어떻게 작동하는지 이해할 수 없습니다.

이를 설명하기 위해 일련의 명령을 제공하겠습니다.

먼저 A B Ctmp 디렉터리 내에 디렉터리를 만들고 새 디렉터리에 새 파일을 만듭니다 abcfile.

user@desktop /tmp
$ pwd
/tmp

user@desktop /tmp
$ mkdir "A B C"

user@desktop /tmp
$ ls
'A B C'

user@desktop /tmp
$ touch "A B C"/abcfile

user@desktop /tmp
$ ls "A B C"/
abcfile

A B C변수에 값을 새로 할당 하고, 디렉토리의 내용을 나열하는 명령을 호출하는 다양한 방법을 $DIR시도해 보겠습니다.ls

user@desktop /tmp
$ DIR="A B C"

변수가 인용되지 않으면 명령이 예상대로 실패합니다.

user@desktop /tmp
$ ls $DIR
ls: cannot access 'A': No such file or directory
ls: cannot access 'B': No such file or directory
ls: cannot access 'C': No such file or directory

변수를 참조한 후 예상대로 작동합니다.

user@desktop /tmp
$ ls "$DIR"
abcfile

명령의 출력을 문자열로 원하는 경우

user@desktop /tmp
$ echo $(ls "$DIR")
abcfile

이 명령은 작동하지만 왜 작동합니까? Shellcheck에 따르면 이것은 실제로 올바르지 않습니다. 변수는 큰따옴표 밖에 있어야 합니다.

user@desktop /tmp
$ echo "$(ls "$DIR")"
abcfile

내부 변수에 큰따옴표가 없으면 명령이 실패합니다.

user@desktop /tmp
$ echo "$(ls $DIR)"
ls: cannot access 'A': No such file or directory
ls: cannot access 'B': No such file or directory
ls: cannot access 'C': No such file or directory

답변1

나는 여러분이 출력 명령의 출력을 echo "$(somecommand)"as로 바꿀 필요가 없으며 이 구성을 단지 예로 사용하고 있다는 것을 알고 있다고 가정합니다.somecommandecho

출력이 인쇄 되므로 명령은 echo $(ls "$DIR")"작동"합니다 .ls "$DIR"abcfileecho

이 경우 여기에 명령 대체를 인용해도 아무런 효과가 없습니다. 파일 이름에 있는 문자를 포함하도록 문자열 을 변경하지 않는 한 문자열에는 abcfile따옴표가 필요하지 않습니다 (아래 이유 참조).$IFS

그러나 다음을 고려하십시오.

A B C/
|-- A*
`-- abcfile

지금:

$ echo "$(ls "$DIR")"
A*
abcfile
$ echo $(ls "$DIR")
A B C abcfile

마지막 출력에서는 파일 이름을 A*디렉터리 이름과 일치하는 파일 이름 와일드카드 패턴으로 확장합니다 A B C. 또한 출력에서 ​​개행 문자가 손실되었음을 알 수 있습니다 ls.

쉘이 손실되기 때문에 개행 문자가 손실됩니다.분사따옴표가 없는 출력에서 ls​​공백, 탭 및 줄 바꿈(의 기본값 $IFS)을 사용하여 단어로 분할합니다.

디렉토리 이름은 A B C단어 분할에 의해 생성된 단어가 포함되어 있으므로 삽입됩니다.파일 이름 생성(와일드카드).

새 파일 이름이 이면 A* A*디렉터리 이름이 두 번 삽입됩니다.

A B C/
|-- A* A*
`-- abcfile
$ echo $(ls "$DIR")
A B C A B C abcfile

관련된:

답변2

이것이 주된 오해인 것 같습니다.

변수는 큰따옴표 밖에 있어야 합니다.

user@desktop /tmp
$ echo "$(ls "$DIR")"
abcfile

변수가 큰따옴표 밖에 있지 않습니다. 쉘은 내부에서 인용을 고려합니다.$() 각기외부에서 인용하는 것보다. 즉, echo "$(ls "$DIR")"큰따옴표 안에는 실제로중첩됨:

echo "$(ls "$DIR")"
#          ^    ^     inner quotes
#    ^            ^   outer quotes

일반적으로 큰따옴표로 묶인 변수는 좋기 때문에그리고전체 명세서 $()에 이러한 인용문이 각각 필요합니다 (인용하고 싶지 않은 경우 제외).

"Quirk 2" 비교이 답변.


부가 질문:

명령의 출력을 문자열로 원하는 경우

user@desktop /tmp
$ echo $(ls "$DIR")
abcfile

stdout에 대한 출력에는 유형이 없으며 echo문자열로 만들지 않습니다. 이 특별한 경우에는 echo아무것도 바뀌지 않지만 다음을 참조하세요.무엇이 잘못되었나요 echo $(stuff)?

관련 정보