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

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

출력이 변수에 할당되더라도 다음과 같이 명령 대체를 인용하는 경향이 있습니다.

var="$(command)"

하지만 이것이 실제로 필요한가? 언제 깨질까요? 수락된 답변여기주장하다:

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

해당 링크는 Grey Cat Wiki의 인용에 관한 훌륭한 페이지로 연결되지만 해당 페이지에서는 인용 명령 대체에 대해 구체적으로 언급하지 않습니다. 그리고 인용하면서바꾸다분명히 필요하지만 quote 명령 대체 자체는 필요하지 않은 것 같습니다.

그러나 같은 기사에서는 다음과 같이 결론을 내렸습니다.

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단계 실행아니요필드 분할이 언급되어 있지만 관련 부분은필드 분할다중 필드 생성에 대한 예외로 변수 할당에 대한 언급도 없습니다.

관련 정보