따옴표없이 공백이있는 매개 변수 확장은 왜 대괄호 "[["내에서 작동하지만 단일 대괄호 "["내에서는 작동하지 않습니까?


85

단일 또는 이중 괄호 사용과 혼동됩니다. 이 코드를보십시오 :

dir="/home/mazimi/VirtualBox VMs"

if [[ -d ${dir} ]]; then
    echo "yep"
fi

문자열에 공백이 있지만 완벽하게 작동합니다. 그러나 단일 브래킷으로 변경하면 :

dir="/home/mazimi/VirtualBox VMs"

if [ -d ${dir} ]; then
    echo "yep"
fi

그것은 말한다 :

./script.sh: line 5: [: /home/mazimi/VirtualBox: binary operator expected

내가 그것을 바꿀 때 :

dir="/home/mazimi/VirtualBox VMs"

if [ -d "${dir}" ]; then
    echo "yep"
fi

잘 작동합니다. 누군가 무슨 일이 일어나고 있는지 설명 할 수 있습니까? "${var}"공백으로 인한 문제를 방지하기 위해 변수 주위에 큰 따옴표를 할당해야 할 때



답변:


83

단일 괄호 [는 실제로 test명령 의 별명이며 구문 이 아닙니다 .

단일 괄호의 단점 중 하나는 많은 피연산자 중 하나 이상이 빈 문자열을 반환하려고 시도하면 두 개의 피연산자 (이진)를 기대한다고 불평한다는 것입니다. 당신은 사람들이 어떻게 볼 이유입니다 [ x$foo = x$blah ]x피연산자가 빈 문자열로 평가하지 않을 것이라는 점을 보증합니다.

이중 브라켓은 [[ ]], 다른 한편으로는, 구문 및보다 훨씬 더 할 수있다 [ ]. 알다시피 단일 피연산자 문제가 없으며 연산자를 사용하여 더 C와 유사한 구문을 사용할 >, <, >=, <=, !=, ==, &&, ||수 있습니다.

나의 추천은 다음과 같습니다 당신의 통역 인 경우 #!/bin/bash, 다음 항상 사용[[ ]]

그것은 점에 유의하는 것이 중요하다 [[ ]]모든 POSIX 쉘에서 지원하지 않는, 그러나 많은 껍질 등을 지원합니까 zshksh에 추가bash


16
빈 문자열 (및 다른 많은) 문제는 따옴표를 사용하여 해결됩니다. 다음 "X"는 또 다른 종류의 문제점을 포함한다 피연산자 로 할 수있다 연산자 . when $foois !or (or -n... ...이 문제는 ( [및 옆에있는 ]) 인수의 수가 4보다 크지 않은 POSIX 쉘에서 문제가되는 것은 아닙니다.
Stéphane Chazelas

21
명확히하는 [ x$foo = x$blah ]것은 [ $foo = $bar ]. [ "$foo" = "$bar" ]POSIX 호환 쉘에서 정확하고 [ "x$foo" = "x$bar" ]Bourne과 같은 쉘에서 작동하지만 x빈 문자열이있는 경우는 아니지만 ... 또는 위치에 $foo있습니다 .!-n
Stéphane Chazelas

1
이 답변에서 흥미로운 의미론. 나는 그것이 * not * 구문 이라는 것이 무엇을 의미하는지 잘 모르겠습니다 . 물론에 [대한 별칭이 아닙니다 test. 그렇다면 test닫는 대괄호를 사용합니다. test -n foo ]. 그러나 test필요하지 않으며 [필요합니다. 다른 모든 측면에서 [동일 test하지만 alias작동 방식 이 아닙니다 . 강타는 설명 [test같은 쉘 내장 명령 하지만, [[A와 쉘 키워드 .
kojiro

1
bash에서 [는 쉘 내장이지만 / usr / bin / [도 실행 파일입니다. 전통적으로 / usr / bin / test에 대한 링크이지만 현대 gnu coreutils는 별도의 바이너리입니다. 일반적인 테스트 버전은 argv [0]을 검사하여 [로 호출되었는지 확인한 다음 일치하는 항목을 찾습니다].
Evan

작동하지 않습니다 내 bash는 >=<=
학생

51

[명령은 일반 명령입니다. 대부분의 쉘은 효율성을 위해 내장 기능을 제공하지만 쉘의 일반적인 구문 규칙을 따릅니다. [는 마지막 인수로 필요하지만 그렇지 않은 test것을 제외하고 는 정확히와 동일합니다 .[]test

이중 괄호 [[ … ]]는 특수 구문입니다. 그것들은 ksh (몇 년 후 [)에 도입되어 [올바르게 사용하기가 번거롭고 [[쉘 특수 문자를 사용하는 새로운 멋진 추가 기능을 제공합니다. 예를 들어

[[ $x = foo && $y = bar ]]

전체 조건식 쉘 해석되기 때문에, 반면에 [ $x = foo && $y = bar ]처음 두 개의 명령어로 분할 될 [ $x = foo$y = bar ]의해 분리 &&연산자. 마찬가지로 이중 괄호를 사용하면 패턴 일치 구문과 같은 항목을 사용할 수 있습니다 (예 : 시작 [[ $x == a* ]]값이 ; 단일 괄호 안에는 현재 디렉토리에서 이름이 시작되는 파일 목록으로 확장 됩니다 . 이중 괄호는 ksh로 처음 소개되었으며 ksh, bash 및 zsh에서만 사용할 수 있습니다.xaa*a

작은 괄호 안에는 대부분의 다른 곳에서와 같이 변수 대체에 큰 따옴표를 사용해야합니다. 왜냐하면 명령에 대한 인수 일뿐 [입니다. 이중 괄호 안에는 셸이 단어 분할이나 글 로빙을 수행하지 않기 때문에 큰 따옴표가 필요하지 않습니다. 명령이 아니라 조건식을 구문 분석합니다.

그러나 [[ $var1 = "$var2" ]]바이트 대 바이트 문자열 비교를 수행하려는 경우 따옴표가 필요한 경우 는 예외입니다 . 그렇지 않으면 $var2일치하는 패턴이됩니다 $var1.

당신이 할 수없는 한 가지는 [[ … ]]변수를 연산자로 사용하는 것입니다. 예를 들어, 이것은 완벽하게 합법적이지만 거의 유용하지 않습니다.

if [ -n "$reverse_sort" ]; then op=-gt; else op=-lt; fi

if [ "$x" "$op" "$y" ]; then 

당신의 예에서

dir="/home/mazimi/VirtualBox VMs"
if [ -d ${dir} ]; then 

내부 명령 if입니다 [4 개 인수 -d, /home/mazimi/VirtualBox, VMs]. 셸은 구문 분석 -d /home/mazimi/VirtualBox한 다음에 수행 할 작업을 모릅니다 VMs. ${dir}올바른 형식의 명령을 얻으려면 단어가 분리되는 것을 방지해야합니다 .

일반적으로 결과에 대해 단어 분할 및 globbing을 수행하려는 경우가 아니면 변수 및 명령 대체에 큰 따옴표를 사용하십시오. 큰 따옴표를 사용하지 않는 것이 안전한 주요 장소는 다음과 같습니다.

  • 대입에서 : foo=$bar(그러나 export "foo=$bar"같은 또는 대입 배열 에서 큰 따옴표가 필요합니다 array=("$a" "$b"));
  • A의 case문 : case $foo in …;
  • =또는 ==연산자 의 오른쪽을 제외한 이중 괄호 안에 (패턴 일치를 원하지 않는 경우) : [[ $x = "$y" ]].

이 모든 것에서 큰 따옴표를 사용하는 것이 맞으므로 고급 규칙을 건너 뛰고 항상 따옴표를 사용할 수 있습니다.


1
@StephaneChazelas 내 실수. [1981 년에 실제로 System III에서 나온 것으로 밝혀졌습니다 .
Gilles

8

"${var}"공백으로 인한 문제를 방지하기 위해 변수 주위에 큰 따옴표를 할당해야 할 때

이 질문에 내재 된 것은

왜 충분하지 않습니까?${variable_name}

${variable_name} 당신이 생각하는 것을 의미하지는 않습니다…

... 당신은 있다고 생각하면 아무것도 (변수 값) 공백으로 인한 문제와 함께 할 수 있습니다. 이것에 좋습니다 :${variable_name}

$ bar=foo
$ bard=Shakespeare
$ echo $bard
Shakespeare
$ echo ${bar}d
food

그리고 다른 것은 없습니다! 1  은변수 이름의 일부가 될 수있는 문자 (문자 (-또는-), 밑줄 () 또는 숫자 (-))로바로 뒤를 따르지 않는 한 아무 효과가 없습니다. 그런 다음에도 문제를 해결할 수 있습니다.${variable_name}AZaz_09

$ echo "$bar"d
food

나는 그것의 사용을 막으려 고 노력하지 않고있다- echo "${bar}d"아마도 여기에서 가장 좋은 해결책 일 것이다. 그러나 사람들 따옴표 대신 에 중괄호에 의존 하거나 또는 본능적으로 중괄호를 적용한 다음“이제 인용이 필요 합니까? ”  정당한 이유가없는 한 항상 따옴표를 사용해야하며 자신이하고있는 일을 확실하게 알 수 있습니다.
_________________
1    물론, 더 멋진 형태의 매개 변수 확장 ( 예 : 및 )이 구문을 기반으로 한다는 사실을 제외하고 . 또한, 당신은 사용할 필요 , 10, 11 등, 위치 매개 변수를 참조, 등 - 따옴표가 당신을 도움이되지 않습니다.${parameter:-[word]}${parameter%[word]}${parameter}${10}${11}


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.