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"둘 다 해결합니다.

³도의 일부 값 실패 ab같은 !(.

⁴ 떠들썩한 파티 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.