Bash 연산자 [[ vs [ vs ( vs ((?

Bash 연산자 [[ vs [ vs ( vs ((?

bash(괄호, 이중 괄호, 대괄호 및 이중 괄호)에서 사용할 때 이러한 연산자가 어떻게 다른지 약간 혼란스럽습니다.

[[ , [ , ( , ((

나는 사람들이 다음과 같은 진술에서 그 표현을 사용하는 것을 보았습니다 if:

if [[ condition ]]

if [ condition ]

if ((condition))

if (condition)

답변1

Bourne과 같은 쉘에서 if명령문은 일반적으로 다음과 같습니다.

if
   command-list1
then
   command-list2
else
   command-list3
fi

thencommand-list1이 절은 명령 목록의 종료 코드가 0인 경우 실행됩니다. 종료 코드가 0이 아니면 else이 절이 실행됩니다. command-list1그것은 간단할 수도 있고 복잡할 수도 있습니다. 예를 들어 , 또는 ;newlines 연산자 중 하나로 구분된 하나 이상의 파이프 시퀀스 일 수 있습니다 . 아래에 표시된 조건은 특별한 경우일 뿐입니다 .&&&||ifcommand-list1

  1. if [ condition ]

    [test전통적인 명령의 또 다른 이름 입니다 . [/는 test표준 POSIX 유틸리티입니다. 모든 POSIX 쉘에는 이 기능이 내장되어 있습니다(POSIX²에서는 필요하지 않지만). 명령 은 test종료 코드를 설정하고 if명령문은 그에 따라 작업을 수행합니다. 일반적인 테스트는 파일이 존재하는지 또는 한 숫자가 다른 숫자와 같은지 여부입니다.

  2. if [[ condition ]]

    test이것은 1의 새로운 업그레이드 변형입니다.케시저것세게 때리다,다루기 힘든,야쉬,바쁜 상자또한 지원됩니다. 이 [[ ... ]]구성은 또한 종료 코드를 설정하고 if명령문은 그에 따라 동작합니다. 확장된 기능 중에서 문자열이 와일드카드 패턴과 일치하는지 여부를 테스트할 수 있습니다.바쁜 상자).

  3. if ((condition))

    다른케시확장 이론세게 때리다그리고다루기 힘든또한 지원됩니다. 그러면 산술 연산이 수행됩니다. 산술 결과로 종료 코드가 설정되고 if그에 따라 명령문이 실행됩니다. 산술 계산 결과가 0이 아니면 종료 코드 0(true)을 반환합니다. 와 마찬가지로 [[...]]이 형식은 POSIX가 아니므로 이식성이 없습니다.

  4. if (command)

    이는 서브셸에서 명령을 실행합니다. 명령이 완료되면 종료 코드가 설정되고 if그에 따라 명령문이 실행됩니다.

    이러한 하위 쉘을 사용하는 일반적인 이유는 command필요한 command변수 할당이나 쉘 환경에 대한 다른 변경으로 인한 부작용을 제한하기 위한 것입니다. 이러한 변경 사항은 서브셸이 완료된 후에는 유지되지 않습니다.

  5. if command

    명령이 실행되고 if명령문은 종료 코드에 따라 동작합니다.

[ ... ]and 에는 [[ ... ]]주변에 공백이 필요하지만 (...)and ((...))에는 필요하지 않습니다.


1 실제 명령은 아니지만 특수한 쉘 구조이지만 구문은 일반 명령과 다르며 서로 다른 쉘 구현 간에는 상당한 차이가 있습니다.

² POSIX에는 시스템에 독립 실행형 유틸리티가 필요 test하지만 [POSIX의 경우 [여러 Linux 배포판에는 이 유틸리티가 부족한 것으로 알려져 있습니다.

답변2

  • (…)괄호는 다음을 나타냅니다.서브쉘. 내부 내용은 다른 많은 언어의 표현과 다릅니다. 이는 명령 목록입니다(대괄호 외부와 마찬가지로). 이러한 명령은 별도의 하위 프로세스에서 실행되므로 대괄호 내부에서 수행된 리디렉션, 할당 등은 대괄호 외부에는 영향을 미치지 않습니다.
    • 앞에 달러 기호가 있는 $(…)것은명령 대체: 대괄호는 출력이 명령줄의 일부로 사용되는 명령을 묶습니다(추가 확장 후, 큰따옴표 사이에 대체가 있는 경우는 제외).다른 이야기).
  • { … }중괄호는 명령을 그룹화한다는 점에서 괄호와 비슷하지만 구문 분석에만 영향을 미치고 그룹화에는 영향을 미치지 않습니다. 프로그램은 2 x=2; { x=4; }; echo $x대신 4를 인쇄합니다 x=2; (x=4); echo $x. (중괄호도 마찬가지입니다.핵심 단어{;명령 위치(따라서 앞뒤 공백 ) 에서는 구분 및 조회가 필요 }하지만 괄호는 그렇지 않습니다. 그것은 단지 구문상의 문제일 뿐입니다. )
    • 앞에 달러 기호가 있는 ${VAR}것은매개변수 확장, 변수 값으로 확장되며 추가 변환을 수행할 수 있습니다. 쉘은 ksh93또한 ${ cmd;}서브쉘을 생성하지 않는 명령 대체 형식을 지원합니다.
  • ((…))이중 괄호가 a를 둘러쌉니다.산술 명령어, 즉 정수에 대한 계산이며 해당 구문은 다른 프로그래밍 언어와 유사합니다. 이 구문은 주로 할당 및 조건문에 사용됩니다. 이는 ksh/bash/zsh에만 존재하며 일반 sh에는 존재하지 않습니다.
    • 산술 표현식에도 동일한 구문이 사용되며 $((…))이는 표현식의 정수 값으로 확장됩니다.
  • [ … ]단일 괄호조건식. 조건식은 주로 다음을 기반으로 합니다.운영자예에는 -n "$variable"변수가 비어 있는지 테스트하고 -e "$file"파일이 존재하는지 테스트하는 것이 포함됩니다. 각 연산자 주위에는 공백이 있어야 하며(예 : not ), [ "$x" = "$y" ]대괄호 안팎에는 [ "$x"="$y" ]공백이나 문자가 필요합니다(예: not ).;[ -n "$foo" ][-n "$foo"]
  • [[ … ]]이중 괄호는 몇 가지 추가 기능이 포함된 조건식의 또 다른 형태입니다. 예를 들어 [[ -L $file && -f $file ]]파일이 일반 파일에 대한 심볼릭 링크인지 확인하는 테스트를 작성할 수 있지만 단일 괄호에는 [ -L "$file" ] && [ -f "$file" ].공백이 있고 따옴표가 없는 매개변수 확장이 이중 괄호 [[ 내에서는 작동하지만 단일 괄호 [에서는 작동하지 않는 이유는 무엇입니까?이 주제에 대한 추가 정보.

껍질에서,모든command는 조건부 명령입니다. 모든 명령에는 성공 시 0, 실패 시 1에서 255 사이의 정수(일부 쉘에서는 더 많을 수 있음)의 반환 상태가 있습니다. 명령 [ … ](또는 구문 형식)은 철자를 입력할 수도 있고 파일이 존재하거나 문자열이 비어 있지 않거나 숫자가 다른 것보다 작을 때 성공하는 [[ … ]]특정 명령입니다 . 숫자가 다른 숫자보다 작을 때 문법적 형태가 성공합니다. 0이 아닙니다. 다음은 쉘 스크립트의 조건문의 몇 가지 예입니다.test …((…))

  • myfile문자열이 포함되어 있는지 테스트합니다 hello.

    if grep -q hello myfile; then …
    
  • mydir디렉터리인 경우 해당 디렉터리로 변경하고 다음을 수행합니다.

    if cd mydir; then
      echo "Creating mydir/myfile"
      echo 'some content' >myfile
    else
      echo >&2 "Fatal error. This script requires mydir to exist."
    fi
    
  • myfile현재 디렉터리에 호출된 파일이 있는지 테스트합니다.

    if [ -e myfile ]; then …
    
  • 동일하지만 매달린 심볼릭 링크도 포함됩니다.

    if [ -e myfile ] || [ -L myfile ]; then …
    
  • x값(숫자로 가정)이 2 이상인지 테스트합니다 .

    if [ "$x" -ge 2 ]; then …
    
  • bash/ksh/zsh의 값(숫자로 가정) x이 2 이상인지 테스트합니다.

    if ((x >= 2)); then …
    

답변3

[그리고[[

[이 답변은 질문의 vs 하위 집합을 다룹니다 .[[

Bash 4.3.11의 몇 가지 차이점:

  • POSIX 및 Bash 확장:

  • 일반 명령과 마법

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

      ]마지막 매개변수 입니다 [.

      Ubuntu 16.04에는 실제로 다음 /usr/bin/[과 같은 실행 파일이 있습니다.핵심 도구, 그러나 bash 내장 버전이 우선합니다.

      Bash가 명령을 구문 분석하는 방식에는 변경된 사항이 없습니다.

      특히 <리디렉션 &&||여러 명령 연결은 ( )이스케이프되지 않는 한 하위 쉘을 생성하고 \단어 확장은 평소와 같이 발생합니다.

    • [[ X ]]X마술처럼 구문 분석할 수 있는 단일 구문입니다. <, , &&, ||및 기타 ()특수 처리에서는 단어 분할 규칙이 다릅니다.

      =및 와 같은 추가 차이점이 있습니다 =~.

    Bashese에서:는 [내장 명령이자 [[키워드입니다.https://askubuntu.com/questions/445749/whats-the-difference-Between-shell-builtin-and-shell-keyword

  • <

  • &&그리고||

    • [[ a = a && b = b ]]: 참이고 논리적이다그리고
    • [ a = a && b = b ]: 구문 오류, &&AND 명령 구분 기호로 구문 분석됨cmd1 && cmd2
    • [ a = a ] && [ b = b ]: POSIX의 안정적인 동등물
    • [ a = a -a b = b ]: 거의 동일하지만 특정 값 a이나 논리 연산으로 해석되는 경우 나 b이상 해서 실패했기 때문에 POSIX에서 더 이상 사용되지 않습니다.!(
  • (

    • [[ (a = a || a = b) && a = b ]]: 잘못된. 그렇지 않은 경우 보다 우선순위가 높 ( )으므로 true가 됩니다.[[ && ]][[ || ]]
    • [ ( a = a ) ]: 구문 오류, ()서브쉘로 해석됨
    • [ \( a = a -o a = b \) -a a = b ]: 동일하지만 POSIX는 , ()및 를 더 이상 사용하지 않습니다 -a. -o없는 경우 참입니다. 우선순위가 다음보다 높기 \( \)때문 입니다.-a-o
    • { [ a = a ] || [ a = b ]; } && [ a = b ]더 이상 사용되지 않는 POSIX와 동일합니다. 그러나 이 특별한 경우에는 다음과 같이 작성할 수 있습니다. [ a = a ] || [ a = b ] && [ a = b ]왜냐하면 ||및 쉘 연산자는 and 및 , 및 와 달리 &&동일한 우선순위를 갖기 때문입니다 .[[ || ]][[ && ]]-o-a[
  • 확장 중 단어 분할 및 파일명 생성(split+glob)

    • 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? ]]: 사실이다, 왜냐하면 그것이 사실이기 때문이다패턴 매칭( * ? [마법입니다). 전역을 현재 디렉터리의 파일로 확장하지 마세요.
    • [ ab = a? ]: a?글로벌 확장. 따라서 현재 디렉터리의 파일에 따라 true 또는 false가 될 수 있습니다.
    • [ ab = a\? ]: false, 전역 확장이 아닙니다.
    • =and 는 및 와 동일 ==하지만 Bash 확장이 있습니다.[[[==
    • case ab in (a?) echo match; esac: POSIX에 해당
    • [[ ab =~ 'ab?' ]]: false, ''Bash 3.2 이상에서는 마법이 사라지고 bash 3.1과의 호환성이 활성화되지 않습니다( 와 동일 BASH_COMPAT=3.1).
    • [[ 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와 동등한 구성이 있습니다.

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

  • 이식성 상실
  • 독자가 또 다른 bash 확장의 복잡성을 배우도록 강요합니다. [특별한 의미가 포함되지 않은 이상한 이름을 가진 일반적인 명령입니다.

감사해요스티븐 차제라스중요한 수정 및 추가가 이루어졌습니다.

답변4

몇 가지 예:

기존 테스트:

foo="some thing"
# check if value of foo is not empty
if [ -n "$foo" ] ; then... 
if test -n "$foo" ; then... 

test[명령은 다른 명령과 같으므로 변수를 따옴표로 묶지 않으면 단어로 분할됩니다.

현대적인 테스트

[[ ... ]]약간 다르게 작동하는 (최신) 특수 쉘 구성으로, 특히 변수를 토큰화하지 않는다는 점에서 주목할 만합니다.

if [[ -n $foo ]] ; then... 

일부문서는 여기 [[[여기 에 있습니다.

산술 테스트:

foo=12 bar=3
if (( $foo + $bar == 15 )) ; then ...  

"일반" 명령:

위의 모든 명령은 일반 명령처럼 작동하며 if모든 명령을 받아들일 수 있습니다.

# grep returns true if it finds something
if grep pattern file ; then ...

여러 명령:

아니면 여러 명령을 사용할 수도 있습니다. 명령 세트를 ( ... )서브셸에 래핑하여 실행하고일시적인셸 상태(작업 디렉터리, 변수)의 복사본입니다. 임시로 다른 디렉토리에서 프로그램을 실행해야 하는 경우:

# this will move to $somedir only for the duration of the subshell 
if ( cd $somedir ; some_test ) ; then ...

# while here, the rest of the script will see the new working
# directory, even after the test
if cd $somedir ; some_test ; then ...

관련 정보