출력을 변수에 할당할 때 명령 대체를 인용해야 합니까?

출력을 변수에 할당할 때 명령 대체를 인용해야 합니까?

나는 출력을 변수에 할당할 때에도 아래와 같이 명령 대체를 인용하는 경향이 있습니다.

var="$(command)"

그래도 실제로 필요한가요? 언제 깨지나요? 허용된 답변여기주장:

DIRNAME="$(디렉터리 이름 $FILE)"당신이 원하는 것을하지 않을 것입니다$FILE에 공백이나 글로빙 문자([?*.

링크는 인용에 관한 Gray Cat Wiki의 훌륭한 페이지를 가리키지만 해당 페이지에서는 명령 대체 인용을 구체적으로 언급하지 않습니다. 그리고 인용하면서변하기 쉬운명령 대체 자체를 인용하는 것은 분명히 필요하지 않은 것 같습니다.

그러나 같은 게시물은 다음과 같이 끝납니다.

DIRNAME="$(dirname "$FILE")" 이 권장되는 방법입니다. 다른 것을 변경하지 않고 DIRNAME=을 명령과 공백으로 바꿀 수 있으며 dirname은 올바른 문자열을 받습니다.

저도 늘 그렇게 생각했고, 여기에서 인용하지 않은 게시물을 자주 수정했습니다. 그러나 위에 링크된 위키 페이지에서는 다음과 같이 주장합니다.

큰따옴표를 안전하게 생략할 수 있는 몇 가지 경우가 있습니다.

간단한 과제의 오른쪽에 있습니다. 따옴표 없이 foo=$bar를 쓸 수 있습니다. 이는 POSIX와 호환됩니다.

[. . . ]

실제로 "간단한" 할당은 아니지만 그럼에도 불구 var=$(command)하고 인용문이 실제로 필요한 경우를 찾을 수 없었습니다.

$ var=$(echo "foo bar baz")  ## whitespace works
$  echo "$var"
foo bar baz

$ var=$(printf "foo\nbar * baz") ## so do globbing characters
$ echo "$var"
foo
bar * baz

$ var1="foo\nbar * baz"
$ var=$(printf "$var1")  ## printing a variable doesn't make any difference
$ echo "$var" 
foo
bar * baz

$ var=$(printf '%s\n' "$var1")
$ echo "$var"
foo\nbar * baz

$ var=$(printf -- '-e %s\n' "$var1") ## strings starting with - also work
$ echo "$var"
-e foo\nbar * baz

물론 명령 대체가 와 같은 것에 직접 사용되는 경우에는 따옴표가 절대적으로 필요 command1 "$(command2)"하지만 변수에 할당할 때는 그렇지 않은 것 같습니다.

그렇다면 내가 무엇을 놓치고 있는 걸까요? 따옴표가 필요한가요? 명령 대체를 인용하는 코너 케이스는 무엇입니까?반환값을 변수에 할당할 때당신을 보호해 주나요? 아니면 변수 할당 작업의 오른쪽에 있는 경우 명령 대체를 인용하지 않아도 항상 괜찮습니까?

답변1

당신은필요하지 않다과제 오른쪽에 있는 표현을 인용하려면

당신을 짜증나게 하는 것은 다른 대답입니다.추천하다그럼에도 불구하고 인용하자면. 그러나 이는 코드 유지 관리에 관한 것입니다.

다음을 고려하세요옳은예:

DIRNAME=$(dirname "$FILE")
echo "debug: dirname is $DIRNAME"
ls "$DIRNAME"

이제 이 스크립트를 사용하고 나면 디버그 메시지가 제거될 수 있다고 생각할 수도 있습니다. 따라서 편집기를 사용하면 에코 라인을 제거할 수 있습니다. 그러면 더 이상 DIRNAME 변수가 필요하지 않으며 ls할당의 왼쪽 사이트를 바꾸기 위해 명령을 이동하기만 하면 됩니다. 이제 당신은 할 수 있습니다필요한 따옴표를 추가하는 것을 잊어버리세요그리고 넌 이걸로 끝이야깨진 스크립트:

ls $(dirname "$FILE")

첫 번째 저자가 쉘 전문가이고 두 번째 편집자가 초보자인 경우 이러한 실수가 발생할 확률은 더욱 높아집니다.

물론 이것이 맞는지는 논란의 여지가 있다휴대용 셸 기능을 피하는 권장 사항정말 유용합니다. 개인적으로 나는 그가 추천하는 대로 주로 그렇게 합니다. 나는 또한 다음과 같은 보다 "간단한" 할당을 위해 이 작업을 수행합니다. var="${foo}"(불필요한 중괄호도 포함)

답변2

하나의 참고사항으로,Bash의 매뉴얼은 이것에 대해 명확합니다.:

변수는 다음 형식의 명령문으로 할당될 수 있습니다.

name=[value]

값이 제공되지 않으면 변수에 널 문자열이 할당됩니다. 모든 값에는 물결표 확장, 매개변수 및 변수 확장, 명령 대체, 산술 확장, 따옴표 제거(자세한 내용은 아래 참조)가 적용됩니다. [...]단어 분할이 수행되지 않습니다., 아래 설명된 "$@"는 제외됩니다.파일 이름 확장이 수행되지 않습니다.

단어 분할이나 파일 이름 확장이 없으므로 따옴표가 필요하지 않습니다.


POSIX의 경우 섹션2.9.1 간단한 명령:

2. 변수 할당이나 방향 재지정이 아닌 단어는 확장되어야 합니다. 확장 후에도 필드가 남아 있는 경우 확장 후에도 필드가 남아 있는 경우 첫 번째 필드는 명령 이름으로 간주되고 나머지 필드는 명령에 대한 인수입니다.
[...]
4. 각 변수 할당은 값을 할당하기 전에 물결표 확장, 매개변수 확장, 명령 대체, 산술 확장 및 따옴표 제거를 위해 확장되어야 합니다.

이것이 필드 분할이 2단계에서 수행된 확장에 대해서만 발생한다는 의미로 해석되어야 하는지 잘 모르겠습니다. 4단계는~ 아니다필드 분할에 대해 언급하지만필드 분할또한 여러 필드를 생성하는 데 대한 예외로 변수 할당을 언급하지 않습니다.

관련 정보