Bash에서 $ (명령 대체) 내 인용


126

내 Bash 환경에서 공백을 포함하는 변수를 사용하고 이러한 변수를 명령 대체 내에서 사용합니다. 불행히도 SE에서 답을 찾을 수 없습니다.

변수를 인용하는 올바른 방법은 무엇입니까? 이것들이 중첩되어 있으면 어떻게해야합니까?

DIRNAME=$(dirname "$FILE")

또는 대체 외부에서 인용합니까?

DIRNAME="$(dirname $FILE)"

아니면 둘다?

DIRNAME="$(dirname "$FILE")"

또는 백틱을 사용합니까?

DIRNAME=`dirname "$FILE"`

이것을하는 올바른 방법은 무엇입니까? 따옴표가 올바르게 설정되어 있는지 쉽게 확인할 수 있습니까?




1
이것은 좋은 질문이지만 공백이 포함 된 모든 문제를 감안할 때 왜 의도적으로 사용하여 스스로 인생을 힘들게 만들 것입니까?
Joe

3
@Joe, 공백이 있으면 파일 이름에 공간이 있습니까? 개인적으로 자주 사용하지는 않지만 공백이 있는지 확실하지 않은 다른 사람들의 디렉토리 및 파일과 작업하고 있습니다. 또한 한 번에 바로 얻는 것이 더 좋으므로 앞으로 걱정할 필요가 없습니다.
CousinCocaine

4
예. 우리는 그 "다른 사람들"과 어떤 관계가 있습니까? <G>
Joe

답변:


188

최악에서 최상의 순서로 :

  • DIRNAME="$(dirname $FILE)" $FILE공백 또는 글 로빙 문자가 포함 된 경우 원하는 작업을 수행하지 않습니다\[?* .
  • DIRNAME=`dirname "$FILE"`기술적으로는 정확하지만 백틱은 중첩시 추가 복잡성으로 인해 명령 확장에 권장되지 않습니다 .
  • DIRNAME=$(dirname "$FILE")이 것이 할당이기 때문에 정확 합니다 . 당신과 같은 다른 상황에서 명령 대체를 사용하는 경우 export DIRNAME=$(dirname "$FILE")또는 du $(dirname "$FILE")확장의 결과가 공백이나 글 로빙 문자가 포함 된 경우, 따옴표의 부족 문제의 원인이됩니다.
  • DIRNAME="$(dirname "$FILE")"권장되는 방법입니다. 당신은 대체 할 수있는 DIRNAME=명령과 다른 것을 변경하지 않고 공백으로하고, dirname올바른 문자열을받습니다.

더 향상 시키려면 :

  • DIRNAME="$(dirname -- "$FILE")"$FILE대시로 시작 하면 작동합니다 .
  • DIRNAME="$(dirname -- "$FILE"; printf x)" && DIRNAME="${DIRNAME%?x}"출력 끝에 $FILE$()바꿈을 잘라 내고 dirname결과 뒤에 줄 바꿈을 출력하기 때문에 줄 바꿈으로 끝나 더라도 작동합니다 . esh dirname, 왜 달라야합니까?

명령 확장을 원하는만큼 중첩 할 수 있습니다. $()항상 새로운 인용 컨텍스트를 작성 하면 다음과 같은 작업을 수행 할 수 있습니다.

foo "$(bar "$(baz "$(ban "bla")")")"

당신은 백틱으로 그것을 시도하고 싶지 않습니다 .


3
내 질문에 대한 명확한 대답. 이 변수를 중첩하면 지금처럼 인용을 계속 할 수 있습니까?
CousinCocaine

3
따옴표 내의 명령 섭씨 내 따옴표의 동작을 자세히 설명하는 참조 / 자원이 있습니까?
AmadeusDrZaius

12
@AmadeusDrZaius " $()항상 새로운 인용 컨텍스트를 만들면"외부 인용 부호와 똑같습니다. 내가 아는 한 더 이상 아무것도 없습니다.
l0b0

4
@ l0b0 고마워요, 네 설명이 아주 분명 했어. 나는 그것이 어딘가에 매뉴얼에 있는지 궁금합니다. wooledge에서 (비공식적이지만) 찾았습니다 . 대체 순서에 대해 주의 깊게 읽으면 그 결과를 얻을 수 있습니다.
AmadeusDrZaius 23

1
따라서 중첩 된 따옴표는 허용되지만 대부분의 구문 색 구성표는 특수한 상황을 감지하지 못하기 때문에 우리를 버립니다. 산뜻한.
Luke Davis

19

로 변수 인용의 효과를 항상 표시 할 수 있습니다 printf.

단어 분할 완료 var1:

$ var1="hello     world"
$ printf '[%s]\n' $var1
[hello]
[world]

var1 인용 된 단어가 없으므로

$ printf '[%s]\n' "$var1"
[hello     world]

var1내부 $()에서 단어 분할 echo "hello" "world":

$ var2=$(echo $var1)
$ printf '[%s]\n' "$var2"
[hello world]

에 단어를 나누지 var1않고 따옴표를 쓰지 않아도 문제가 없습니다 $().

$ var2=$(echo "$var1")
$ printf '[%s]\n' "$var2"
[hello     world]

var1다시 나누는 단어 :

$ var2="$(echo $var1)"
$ printf '[%s]\n' "$var2"
[hello world]

두 가지를 인용하면 가장 쉬운 방법입니다.

$ var2="$(echo "$var1")"
$ printf '[%s]\n' "$var2"
[hello     world]

글 로빙 문제

변수를 인용하지 않으면 내용이 크게 확장 될 수 있습니다.

$ mkdir test; cd test; touch file1 file2
$ var="*"
$ printf '[%s]\n' $var
[file1]
[file2]
$ printf '[%s]\n' "$var"
[*]

변수가 확장 된 후에 만 ​​발생합니다. 할당하는 동안 glob를 인용 할 필요는 없습니다.

$ var=*
$ printf '[%s]\n' $var
[file1]
[file2]
$ printf '[%s]\n' "$var"
[*]

set -f이 동작을 비활성화 하려면 사용하십시오 .

$ set -f
$ var=*
$ printf '[%s]\n' $var
[*]

그리고 set +f그것을 다시 활성화 :

$ set +f
$ printf '[%s]\n' $var
[file1]
[file2]

8
사람들은 단어 분리가 유일한 문제가 아니라는 것을 잊는 경향이 var1='hello * world'있습니다. 글 로빙 문제를 설명 하기 위해 예를 바꾸고 싶을 수도 있습니다.
Stéphane Chazelas

10

허용 된 답변에 추가 :

나는 일반적으로 @ l0b0의 대답에 동의하지만 , "가장 최악의"목록에 베어 백틱을 배치하는 것이 적어도 부분적으로 $(...)어디서나 볼 수 있는 가정의 결과라고 생각합니다 . 나는 질문이 Bash를 지정한다는 것을 알고 있지만 Bash가 의미로 밝혀 질 때가 많으며 /bin/sh실제로는 항상 Bourne Again 쉘이 아닐 수도 있습니다.

특히, 일반 Bourne 쉘은 수행 할 작업을 알 수 없습니다 $(...)주장 스크립트가 호환 될 수 있도록 (예를 통해, #!/bin/sh실제로 "진짜"에 의해 실행되는 경우 오작동 가능성이 것입니다 오두막 라인) /bin/sh이이다 - init 스크립트를 생성하거나 사전 및 사후 스크립트를 패키징 할 때 특별한 관심이 있으며 기본 시스템을 설치하는 동안 놀라운 곳에 배치 할 수 있습니다.

이 변수로 할 계획 인 것처럼 들리면 중첩은 스크립트를 실제로 예상대로 실행하는 것보다 걱정할 필요가 없습니다. 대소 문자가 충분하고 이식성이 중요한 경우 스크립트 가 Bash 인 시스템에서 일반적으로 실행될 것으로 예상하더라도 /bin/sh중첩 때문에 여러 할당을 사용하여 이러한 이유로 백틱을 사용하는 경향이 있습니다.

모든 것을 말했듯이, $(...)(Bash, Dash 등) 구현하는 보편적 인 쉘 은 대부분의 경우 더 예쁘고, 더 쉽고, 가장 최근에 선호되는 POSIX 구문을 고수 할 수있는 좋은 자리에 있습니다. @ l0b0이 언급 한 모든 이유.

따로 : 이것은 때때로 StackOverflow에서도 나타났습니다 –


// 훌륭한 답변입니다. 과거에도 / bin / sh와의 호환성 문제가 발생했습니다. 이전 버전과 호환되는 방법을 사용하여 문제를 해결하는 방법에 대한 조언이 있습니까?
Nathan Basanese 2016 년

내 경험에 따르면 : 때로는 백틱을 동봉 된 달러 파엔으로 변경해야 할 수도 있습니다. 쉘 코드가 아닌 Javascript 코드로만 백틱을 작성합니다.
Steven Lu
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.