Bash의 대괄호 []보다 이중 대괄호 [[]]가 선호됩니까?


574

동료는 최근 코드 검토 에서 구조가 다음과 같은 구조 [[ ]]보다 선호되어야 한다고 주장했습니다.[ ]

if [ "`id -nu`" = "$someuser" ] ; then 
     echo "I love you madly, $someuser"
fi

그는 근거를 제시 할 수 없었다. 하나 있습니까?


19
때로는 자신에 대한 깊은 설명 :로를 필요로하지 않고 조언을들을 수 있도록, 융통성 [[코드가 좋은 분명하다 그것으로,하지만 그 날을 기억 할 때 포트거야 아닌 기본 쉘 시스템에서 귀하의 scriptworks bash또는 ksh, 등 [은 추악하고 성가 시지만 AK-47어떤 상황에서도 작동 합니다.
— 루크

178
@rook 자세한 설명없이 조언을들을 수 있습니다. 그러나 당신이 설명을 요청하고 그것을 얻지 못하면, 그것은 일반적으로 붉은 깃발입니다. "신뢰하지만 확인하십시오"그리고 그 모든 것.
— Josip Rodin


1
다시 말해 @rook은 "당신이 말한 것을하고 질문하지 않습니다"
— 글리프

@rook 이해가되지 않았다.
— Rakib

답변:


607

[[놀라움이 적고 일반적으로 사용하는 것이 더 안전합니다. 그러나 이식성이 없습니다-POSIX는 수행하는 작업을 지정하지 않으며 일부 쉘 만 지원합니다 (bash 외에도 ksh도 지원한다고 들었습니다). 예를 들어, 할 수 있습니다

[[ -e $b ]]

파일이 있는지 테스트합니다. 그러나에 [, 당신은 인용이 $b는 인수를 분할하고 같은 일을 확장하기 때문에, "a*"(여기서 [[문자 그대로 소요). 그것은 또한 [외부 프로그램이 될 수있는 방법 과 관련이 있으며 다른 모든 프로그램과 마찬가지로 정상적으로 인수를 수신합니다 (내장 프로그램 일 수도 있지만 여전히이 특별한 처리 기능은 없습니다).

[[=~C와 같은 언어로 알려진 연산자 와 함께 정규 표현식 일치와 같은 다른 멋진 기능 도 있습니다. 여기에 좋은 페이지가 있습니다 : 테스트 [와 의 차이점은 무엇입니까 [[? 및 배쉬 테스트


21
배쉬가 요즘 어디에나 있다는 것을 고려할 때, 나는 그것이 휴대용이라고 생각하는 경향이 있습니다. 나를위한 유일한 일반적인 예외는 busybox 플랫폼입니다.하지만 하드웨어가 실행되는 경우 어쨌든 특별한 노력을 기울이고 싶을 것입니다.
— 총

14
@ 총 : 실제로. 두 번째 문장이 첫 번째 문장을 반증하는 것이 좋습니다. 소프트웨어 개발을 전체적으로 고려한다면, "bash는 어디에나 있습니다"와 "exception is busybox 플랫폼은"완전히 호환되지 않습니다. busybox는 임베디드 개발에 널리 보급되어 있습니다.
— 궤도에서 가벼움 경주

11
@ guns : bash가 내 상자에 설치되어 있어도 스크립트를 실행하지 않을 수 있습니다 (FreeBSD 및 Ubuntu의 표준과 같이 / bin / sh가 일부 대시 변수에 심볼릭 링크되어있을 수 있습니다). Busybox에는 또 다른 이상한 점이 있습니다. 요즘 표준 컴파일 옵션을 사용하면 구문 분석하지만와 [[ ]]동일한 의미로 해석됩니다 [ ].
— dubiousjim

59
@dubiousjim : bash 전용 구문 (이와 같은)을 사용하는 경우 #! / bin / sh가 아닌 #! / bin / bash가 있어야합니다.
— Nick Matteo

16
그렇기 때문에 스크립트를 사용 #!/bin/sh하지만 #!/bin/bashBASH 특정 기능에 의존하자마자 Bourne 쉘이 더 이상 이식 가능하지 않다는 것을 나타내도록 스크립트 를 전환합니다 .
— 앤서니

151

행동 차이

Bash 4.3.11과의 차이점 :

  • POSIX vs Bash 확장 :

  • 정규 명령 대 마법

    • [ 이상한 이름을 가진 일반적인 명령입니다.

      ][추가 인수가 사용되지 않도록 하는 인수입니다 .

      우분투 16.04는 실제로 coreutils 가 /usr/bin/[제공 하는 실행 파일을 가지고 있지만 bash 내장 버전이 우선합니다.

      Bash가 명령을 구문 분석하는 방식에는 아무런 변화가 없습니다.

      특히, <리디렉션,이다 &&와 ||, CONCATENATE 여러 명령 ( )에 의해 탈출하지 않는 한 서브 쉘을 생성 \하고, 단어 확장은 평소와 같이 발생합니다.

    • [[ X ]]X마술처럼 파싱 하는 단일 구문입니다. <, &&, ||및 ()특수 처리, 워드 분할 규칙이 다릅니다된다.

      같은 더 차이도있다 =하고 =~.

      Bashese에서 : [내장 명령이며 [[키워드입니다 : /ubuntu/445749/whats-the-difference-between-shell-builtin-and-shell-keyword

  • <

  • && 과 ||

    • [[ a = a && b = b ]]: 진실하고 논리적 이며
    • [ a = a && b = b ]: &&AND 명령 구분자로 구문 분석 된 구문 오류cmd1 && cmd2
    • [ a = a -a b = b ]: POSIX³에서는 동일하지만 더 이상 사용되지 않습니다.
    • [ a = a ] && [ b = b ]: POSIX 및 신뢰할 수있는 제품
  • (

    • [[ (a = a || a = b) && a = b ]]: 거짓
    • [ ( a = a ) ]: 구문 오류, ()서브 쉘로 해석
    • [ \( a = a -o a = b \) -a a = b ]: 동등하지만 ()POSIX에서 사용되지 않습니다.
    • { [ a = a ] || [ a = b ]; } && [ a = b ] POSIX 상당
  • 확장시 단어 분리 및 파일 이름 생성 (분할 + 글로브)

    • x='a b'; [[ $x = 'a b' ]]: 따옴표가 필요하지 않습니다.
    • x='a b'; [ $x = 'a b' ]: 구문 오류, 확장 [ a b = 'a b' ]
    • x='*'; [ $x = 'a b' ]: 현재 디렉토리에 둘 이상의 파일이 있으면 구문 오류가 발생합니다.
    • x='a b'; [ "$x" = 'a b' ]: POSIX 상당
  • =

    • [[ ab = a? ]]: 패턴 일치 ( * ? [매직) 이기 때문에 true 입니다. 현재 디렉토리의 파일로 확장하지 않습니다.
    • [ ab = a? ]: a?글로브가 확장됩니다. 따라서 현재 디렉토리의 파일에 따라 true 또는 false 일 수 있습니다.
    • [ ab = a\? ]: false, glob 확장이 아님
    • =와 ==모두 동일 [하고 [[있지만, ==배쉬 확장입니다.
    • case ab in (a?) echo match; esac: POSIX 상당
    • [[ ab =~ 'ab?' ]]: 거짓 ⁴, 마법을 잃는다 ''
    • [[ ab? =~ 'ab?' ]]: 진실
  • =~

    • [[ ab =~ ab? ]]: POSIX 확장 정규 표현식 일치, ?확장하지 않음
    • [ a =~ a ]: 구문 오류. bash와 동등한 것은 없습니다.
    • printf 'ab\n' | grep -Eq 'ab?': POSIX 동등 (단일 데이터 만)
    • awk 'BEGIN{exit !(ARGV[1] ~ ARGV[2])}' ab 'ab?': POSIX 상당.

권장 사항 : 항상 사용하십시오 [].

[[ ]]내가 본 모든 구성에 대해 POSIX 등가물 이 있습니다.

당신이 당신을 사용하는 경우 [[ ]]:

  • 휴대 성을 잃다
  • 독자가 다른 배쉬 확장의 복잡성을 배우도록 강요하십시오. [이상한 의미를 가진 일반적인 명령이며 특별한 의미가 없습니다.

¹ [[...]]Korn 쉘 의 동등한 구성에서 영감을 받음

² 그러나 a또는 b(와 같은 +또는 index) 의 일부 값에는 실패하고 10 진수 정수 a와 같으면 숫자 비교를 수행합니다 b. expr "x$a" '<' "x$b"둘 다 해결합니다.

³도의 일부 값 실패 a나 b같은 !나 (.

⁴ 떠들썩한 파티 3.2 이상 3.1 배시에 제공 상용 성 (와 같이 사용할 수 없습니다 BASH_COMPAT=3.1)

shell 및 쉘 연산자 ( 및 연산자 또는 / 연산자 와 반대 )가 동일한 우선 순위를 갖기 때문에 그룹화 (여기서 {...;}명령 그룹을 사용 (...)하여 불필요한 서브 쉘을 실행 함)는 필요하지 않습니다 . 따라서 동일합니다.||&&||&& [[...]]-o-a [[ a = a ] || [ a = b ] && [ a = b ]


4
좋은 설명입니다. 나는 [같은 이유로 사용 합니다.
— Gordon

2
Bashese에서 :) ha. POSIX를 고수해야 할 차이점과 이유에 대한 명확한 설명.
— Jonathan Komar

56

[[ ]]더 많은 기능이 있습니다. 자세한 내용은 Advanced Bash 스크립팅 안내서 를 참조하십시오. 특히 7 장의 확장 테스트 명령 섹션을 참조하십시오 .

또한, 가이드 노트로서 [[ ]]ksh88 (1988 년 Korn 쉘)에 도입되었습니다.


5
이것은 bashism과는 거리가 멀며 Korn 쉘에서 처음 소개되었습니다.
— Henk Langeveld

6
@Thomas, ABS는 실제로 많은 서클에서 매우 열악한 참조로 간주됩니다. 정확한 정보를 많이 가지고 있지만 예제에서 나쁜 관행을 보여주지 않도록 거의 신경 쓰지 않고 수명을 유지하기 위해 많은 시간을 보냈습니다.
— Charles Duffy

@CharlesDuffy 귀하의 의견에 감사드립니다, 당신은 좋은 대안의 이름을 지정할 수 있습니다. 저는 쉘 스크립팅 전문가가 아니며, 반년마다 한 번씩 스크립트 작성에 관해 상담 할 수있는 안내서를 찾고 있습니다.
— 토마스

9
@Thomas, Wooledge BashFAQ 및 관련 위키는 내가 사용하는 것입니다. Freenode #bash 채널의 수십 명이 적극적으로 관리하고 있습니다. BashFAQ # 31, mywiki.wooledge.org/BashFAQ/031 은이 질문과 직접 ​​관련된 페이지입니다.
— Charles Duffy

13

에서 어떤 비교, 테스트, 브래킷 또는 이중 브라켓, 빠른입니까? ( http://bashcurescancer.com )

이중 괄호는“복합 명령”으로, 테스트와 단일 괄호는 쉘 내장입니다 (실제로 같은 명령). 따라서 단일 괄호와 이중 괄호는 다른 코드를 실행합니다.

테스트 및 단일 브래킷은 별도의 외부 명령으로 존재하므로 가장 이식성이 뛰어납니다. 그러나 원격으로 최신 버전의 BASH를 사용하는 경우 이중 괄호가 지원됩니다.


7
가장 빠른 쉘 스크립트에 대한 집착은 무엇입니까 ? 나는 그것이 가장 휴대 하기를 원 하고 개선 [[이 가져올 수있는 것에 대해서는 신경 쓰지 않았습니다 . 그러나 나는 구식 구식 방귀입니다 :-)
— Jens

1
나는 많은 쉘 버전의 내장 증명 생각 [하고 test심지어 외부 버전도 존재하지만.
— dubiousjim

4
@Jens는 일반적으로 동의합니다 : 스크립트의 전체 목적은 이식성입니다 (그렇지 않으면 스크립트가 아닌 코드 및 컴파일입니다) ... 내가 생각할 수있는 두 가지 예외는 다음과 같습니다 (1) 탭 완성 (어디에서 완성 스크립트는 많은 조건부 논리로 인해 실제로 오래 걸릴 수 있습니다). 및 (2) 슈퍼 프롬프트 ( PS1=...crazy stuff...및 / 또는 $PROMPT_COMMAND); 이를 위해 스크립트 실행이 지연 되는 것을 원하지 않습니다 .
— 마이클

1
가장 빠른 강박 관념 중 일부는 단순히 스타일입니다. 다른 모든 것들이 동일합니다. 왜 더 효율적인 코드 구성을 기본 스타일에 통합하지 않습니까? 이식성에 관한 한, bash가 적합한 많은 작업은 본질적으로 이식성이 없습니다. 예를 들어, apt-get update마지막으로 실행 된 후 X 시간 이상 지난 경우에는 실행해야 합니다. 이미 너무 긴 코드 제약 목록에서 이식성을 유지할 수있는 경우 큰 도움이됩니다.
— Ron Burk

5

Google 스타일 가이드 를 따르는 경우 :

테스트 [및[[

[[ ... ]]아니오 경로 이름 확장으로 에러를 감소 시키거나 단어 분할 사이에 발생 [[하고 ]], 그리고 [[ ... ]]정규 표현 매칭을 허용 [ ... ]하지 않는다.

# This ensures the string on the left is made up of characters in the
# alnum character class followed by the string name.
# Note that the RHS should not be quoted here.
# For the gory details, see
# E14 at https://tiswww.case.edu/php/chet/bash/FAQ
if [[ "filename" =~ ^[[:alnum:]]+name ]]; then
  echo "Match"
fi

# This matches the exact pattern "f*" (Does not match in this case)
if [[ "filename" == "f*" ]]; then
  echo "Match"
fi

# This gives a "too many arguments" error as f* is expanded to the
# contents of the current directory
if [ "filename" == f* ]; then
  echo "Match"
fi

1
Google은 " 경로 확장 없음 ... "을 작성했지만 [[ -d ~ ]]true를 반환합니다 ( ~로 확장 됨을 의미 함 /home/user). 나는 구글의 글이 더 정확해야한다고 생각한다.
— JamesThomasMoon1979

2

사용할 수없는 일반적인 상황 [[은 autotools configure.ac 스크립트에 있으며, 대괄호에는 특수하고 다른 의미가 있으므로 또는 test대신에 사용해야 합니다 .-테스트하고 동일한 프로그램입니다.[[[[


2
autotools가 POSIX 셸이 아니라면 왜 [POSIX 셸 함수로 정의 될 것입니까?
— Gordon

autoconf 스크립트는 쉘 스크립트처럼 보이고 쉘 스크립트를 생성하며 대부분의 쉘 명령은 그 안에서 작동합니다.
— vy32

-1

[[]] 이중 괄호는 특정 버전의 SunOS에서 지원되지 않으며 다음과 같이 함수 선언 내부에서 완전히 지원되지 않습니다. GNU bash, 버전 2.02.0 (1) -release (sparc-sun-solaris2.6)


1
매우 중요하며 전혀 중요하지 않습니다. 이전 버전의 bash 이식성은 고려해야합니다. 사람들은 "bash는 어디에서나 유능한 OS를 제외하고 어디에서나 사용 가능하다"고 말합니다. 하지만 필자의 경험에 의하면 solaris는 이식성에 특별한주의를 기울여야하는 플랫폼 중 하나입니다. 최신 OS, 배열, 함수 등의 문제 / 버그; 그러나 tr, sed, awk, tar와 같은 유틸리티 (스크립트에서 사용)조차도 해결 해야하는 solaris에 이상한 점과 특징이 있습니다.
— 마이클

2
솔직히 POSIX 이외의 유틸리티는 너무 많으니 "df"출력과 인수를 살펴보십시오. Shame on Sun. 바라건대 (캐나다 제외) 조금씩 사라지고 있기를 바랍니다.
— 청소부

7
솔라리스 2.6? 1997 년에 출시되어 2006 년에 지원이 종료되었습니다. 그래도 계속 사용하고 있다면 다른 문제가있는 것 같습니다. 덧붙여서 그것은 이중 괄호를 도입 한 Bash v2.02를 사용했기 때문에 그와 같은 오래된 것에서도 작동해야합니다. 2005 년의 Solaris 10은 Bash 3.2.51을 사용했고 2011 년의 Solaris 11은 Bash 4.1.11을 사용했습니다.
— peterh

1
스크립트 이식성. Linux 시스템에는 일반적으로 각 도구의 에디션 만 있으며 이는 GNU 에디션입니다. Solaris에서는 일반적으로 Solaris 네이티브 에디션 또는 GNU 에디션 (Solaris tar vs GNU Tar) 중에서 선택할 수 있습니다. GNU 특정 확장에 의존하는 경우 이식 가능하도록 스크립트에 명시해야합니다. 솔라리스에서는 GNU grep을 원한다면 "g"를 접두어로 붙여서 ggrep와 같이하면됩니다.
— peterh

-2

간단히 말해서, [[다른 프로세스를 포크하지 않기 때문에 더 좋습니다. 다른 프로세스를 분기하기 때문에 대괄호 나 단일 대괄호는 이중 대괄호보다 느립니다.


8
Test 및 [는 bash에서 동일한 내장 명령의 이름입니다. type [이것을 사용하여보십시오 .
— AB

1
@alberge는 사실이지만 [[,와 구별되는 바와 같이 [bash 명령 줄 인터프리터가 구문을 해석합니다. bash에서을 입력하십시오 type [[. unix4linux는 고전적인 Bourne-shell [테스트에서 진리 값을 결정하기 위해 새로운 프로세스를 분기 했지만 [[구문 (ksh에서 bash, zsh 등으로 차용)은 그렇지 않습니다.
— 팀 길버트

2
@Tim, 당신이 말하는 Bourne 쉘이 확실하지 않지만 [Bash뿐만 아니라 Dash ( /bin/sh모든 Debian 파생 Linux 배포판)에 내장되어 있습니다.
— AB

1
아, 무슨 말인지 알 겠어. 예를 들어, 이전 Solaris 또는 HP / UX 시스템에서 / bin / sh와 같은 것을 생각하고 있었지만 물론 [[또는 둘 중 하나를 사용하지 않는 시스템과 호환되어야하는 경우도 있습니다.
— Tim Gilbert

1
@alberge Bourne 쉘은 Bash가 아닙니다 (일명 Bourne Again SHell ).
— kiamlaluno
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.