Bash 연산자의 차이점은 무엇입니까 [[vs [vs (vs ((?

이 연산자가 언제 다르게 수행하는지에 대해 약간 혼란 스럽습니다. bash에서 사용됩니다 (대괄호, 이중 대괄호, 괄호 및 이중 괄호).

[[ , [ , ( , (( 

사람들이 다음과 같은 if 문에서 사용하는 것을 보았습니다.

if [[condition]] if [condition] if ((condition)) if (condition) 

댓글

답변

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

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

then 절은 명령 목록이 0입니다. 종료 코드가 0이 아니면 else 절이 실행됩니다. command-list1는 단순하거나 복잡 할 수 있습니다. 예를 들어 ;, &, &&, || 또는 줄 바꿈. 아래 표시된 if 조건은 command-list1의 특별한 경우입니다.

  1. if [ condition ]

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

  2. if [[ condition ]]

    bash , zsh , ksh 에서 test ¹의 새로운 업그레이드 된 변형입니다. em> yash , busybox sh 도 지원합니다.이 [[ ... ]] 구문은 종료 코드와 if 문은 그에 따라 작동합니다. 확장 기능 중에서 문자열이 와일드 카드 패턴과 일치하는지 테스트 할 수 있습니다 ( busybox sh 에 없음).

  3. if ((condition))

    bash zsh 도 지원하는 다른 ksh 확장 프로그램입니다. 이것은 산술을 수행합니다. 산술의 결과로 종료 코드가 설정되고 if 문이 작동합니다. rdingly. 산술 계산 결과가 0이 아니면 종료 코드 0 (참)을 반환합니다. [[...]]와 마찬가지로이 양식은 POSIX가 아니므로 이식 할 수 없습니다.

  4. if (command)

    이것은 서브 쉘에서 명령을 실행합니다. 명령이 완료되면 종료 코드를 설정하고 if 문이 그에 따라 작동합니다.

    이와 같은 하위 셸을 사용하는 일반적인 이유는 다음과 같은 부작용을 제한하기위한 것입니다. command command에 셸 환경에 대한 변수 할당 또는 기타 변경이 필요한 경우. 이러한 변경은 하위 셸이 완료된 후에 유지되지 않습니다.

  5. if command

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


¹ 실제로는 명령이 아니라 일반 명령과는 별도의 구문을 가진 특수 쉘 구조이지만, 셸 구현에 따라 크게 다릅니다.

² POSIX에는 독립형 test[ 유틸리티를 사용할 수 있지만 [의 경우 여러 Linux 배포판이 m으로 알려져 있습니다.

댓글

  • 5 번째 옵션을 포함 해 주셔서 감사합니다. ‘이 실제로 작동하는 방식을 이해하는 열쇠이며 놀랍게도 활용률이 낮습니다.
  • [는 실제로 내부 명령이나 기호가 아닌 바이너리입니다. 일반적으로 /bin에 거주합니다.
  • @JulienR. 실제로 [test와 마찬가지로 내장되어 있습니다. 호환성을 위해 사용할 수있는 바이너리 버전이 있습니다. help [help test를 확인하세요.
  • while ((isnt POSIX, $(( 즉, 산술 확장은 ‘ 혼동하기 쉽습니다. 종종 해결 방법은 [ $((2+2)) -eq 4 ]와 같은 것을 사용하는 것입니다. 조건문에서 산술을 사용하기 위해
  • 이 답변을 두 번 이상 찬성 할 수 있으면 좋겠습니다. 완벽한 설명입니다.

답변

  • (…) 괄호는 서브 쉘 . 그 안에있는 것은 다른 많은 언어와 같은 표현이 아닙니다. 이는 명령 목록입니다 (외부 괄호와 마찬가지로). 이러한 명령은 별도의 하위 프로세스에서 실행되므로 괄호 안에서 수행되는 리디렉션, 할당 등은 괄호 외부에 영향을주지 않습니다.
    • 달러 기호, $(…) 명령 대체 : 괄호 안에 명령이 있고 명령의 출력 명령 줄의 일부로 사용됩니다 (대체가 큰 따옴표 사이에 있지 않는 한 추가 확장 후, 다른 이야기 ).
  • { … } 중괄호는 명령을 그룹화한다는 점에서 괄호와 비슷하지만 그룹화가 아닌 구문 분석에만 영향을줍니다. 프로그램 x=2; { x=4; }; echo $x는 4를 인쇄하는 반면 x=2; (x=4); echo $x는 2를 인쇄합니다 (중괄호는 키워드 로 구분되어야하며 명령 위치에 있습니다 (따라서 { 뒤의 공백 및 } 앞의 ;). 반면 괄호는 그렇지 않습니다. 이는 단지 구문상의 문제 일뿐입니다.)
    • 선행 달러 기호가있는 ${VAR} 매개 변수 확장 , 가능한 추가 변환으로 변수 값으로 확장. ksh93 셸은 하위 셸을 생성하지 않는 명령 대체 형식으로 ${ cmd;}도 지원합니다.
  • ((…)) 이중 괄호는 산술 명령어 를 둘러싸고 있습니다. 즉, 정수에 대한 계산입니다. 다른 프로그래밍 언어와 유사한 구문입니다.이 구문은 대부분 할당 및 조건에 사용됩니다. 일반 sh가 아닌 ksh / bash / zsh에만 있습니다.
    • 산술 표현식

      , 표현식의 정수 값으로 확장됩니다.

  • [ … ] 단일 괄호로 묶습니다. 조건식 . 조건식은 대부분 iv id = “303f841eb7과 같은 연산자 를 기반으로합니다. “>

는 변수가 비어 있는지 테스트하고-e "$file"는 파일이 있는지 테스트합니다. 각 주위에 공백이 필요합니다. 연산자 (예 : [ "$x"="$y" ] 가 아닌[ "$x" = "$y" ]) 및 공백 또는;대괄호 내부와 외부 모두 (예 : [-n "$foo"] 가 아니라[ -n "$foo" ]).

  • [[ … ]] 이중 괄호는 몇 가지 추가 기능이있는 ksh / bash / zsh에서 조건식의 대체 형식입니다. 예를 들어 는 파일이 일반 파일에 대한 심볼릭 링크인지 테스트하는 반면 단일 대괄호에는 [ -L "$file" ] && [ -f "$file" ]가 필요합니다. 이 주제에 대한 자세한 내용은 따옴표없는 공백이있는 매개 변수 확장이 이중 괄호 [[에서 작동하지만 단일 괄호 [? 는 작동하지 않는 이유]를 참조하십시오.
  • 셸에서 every 명령은 조건부 명령입니다. 모든 명령은 성공을 나타내는 0 또는 1에서 255 사이의 정수 (일부 셸에서는 더 많음)를 나타내는 반환 상태를 갖습니다. 실패. [ … ] 명령 (또는 [[ … ]] 구문 형식)은 철자가 test … 인 특정 명령입니다. div> 파일이 존재하거나 문자열이 비어 있지 않거나 숫자가 다른 숫자보다 작을 때 성공합니다. ((…)) 구문 형식은 숫자가 0이 아닐 때 성공합니다. .다음은 셸 스크립트의 몇 가지 조건문 예입니다.

    • myfilehello :

      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 이상인지 테스트합니다. / p>

      if [ "$x" -ge 2 ]; then … 
    • x (숫자로 간주 됨)의 값이 있는지 테스트합니다. bash / ksh / zsh에서 최소 2 개 :

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

    댓글

    • 단일 괄호는 &&-a를 지원합니다. / div>, 그래서 다음과 같이 쓸 수 있습니다 : [ -L $file -a -f $file ], 이는 여분의 [

    • @AlexisWilke 연산자 -a-o는 관련된 피연산자 중 일부가 연산자처럼 보이는 경우 잘못된 구문 분석으로 이어질 수 있기 때문에 문제가 있습니다. 그래서 ‘ 그것을 언급하지 않는 이유입니다. ‘ 그것들은 이점이없고 ‘ 항상 작동하지는 않습니다. 그리고 타당한 이유없이 인용되지 않은 변수 확장을 작성하지 마십시오. [[ -L $file -a -f $file ]]는 괜찮지 만 단일 괄호를 사용하려면 [ -L "$file" -a -f "$file" ]가 필요합니다 (예 : $file는 항상 / 또는 ./로 시작합니다.
    • 참고 ‘의 [[ -L $file && -f $file ]] ([[...]] 변형).

    답변

    [[[

    이 답변은 [ 대 질문의 [[ 하위 집합

    Bash 4.3.11의 일부 차이점 :

  • (

    • [[ (a = a || a = b) && a = b ]] : 거짓. ( )가 없으면 [[ && ]][[ || ]]
    • 보다 우선하기 때문에 참이됩니다.

    • [ ( a = a ) ] : 구문 오류, ()는 하위 셸로 해석됩니다.
    • [ \( a = a -o a = b \) -a a = b ] : 동일하지만 (), -a-o는 더 이상 사용되지 않습니다. POSIX에 의해. \( \)가 없으면 -a-o
    • 보다 우선 순위가 높기 때문에 true가됩니다.

    • { [ a = a ] || [ a = b ]; } && [ a = b ] 지원 중단되지 않은 POSIX와 동일합니다. 하지만이 특별한 경우에는 [ a = a ] || [ a = b ] && [ a = b ] 만 작성할 수 있습니다. ||&& 셸 연산자는 [[ || ]][[ && ]]-o, -a[
  • 확장시 단어 분할 및 파일 이름 생성 (split + glob )

    • x="a b"; [[ $x = "a b" ]] : true, 따옴표 필요 없음
    • x="a b"; [ $x = "a b" ] : 구문 오류, [ a b = "a b" ]
    • 로 확장 됨

    • x="*"; [ $x = "a b" ] : 현재 디렉토리에 파일이 두 개 이상있는 경우 구문 오류 .
    • x="a b"; [ "$x" = "a b" ] : POSIX 상당
  • =

    • [[ ab = a? ]] : true, 패턴 일치 ( * ? [는 마법입니다). glob이 f로 확장되지 않습니다. 현재 디렉토리의 파일.
    • [ ab = a? ] : a? glob이 확장됩니다. 따라서 현재 디렉토리의 파일에 따라 true 또는 false가 될 수 있습니다.
    • [ ab = a\? ] : false, glob 확장이 아님
    • ===[[[이지만 ==는 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 확장 정규식 일치, ?가 glob 확장되지 않음
    • [ a =~ a ] : 구문 오류. 해당하는 bash가 없습니다.
    • printf "ab\n" | grep -Eq "ab?" : POSIX에 해당 (한 줄 데이터 만 해당)
    • awk "BEGIN{exit !(ARGV[1] ~ ARGV[2])}" ab "ab?" : POSIX 상당.
  • 권장 사항 : 항상 []

    내가 본 모든 [[ ]] 구조에 대해 POSIX가 있습니다.

    [[ ]]를 사용하는 경우 :

    • 이동성을 잃습니다
    • 독자가 다른 bash 확장의 복잡성을 배우도록합니다. [는 이상한 이름의 일반 명령 일 뿐이며 특별한 의미가 없습니다.

    Stéphane Chazelas (중요한 수정 및 추가)

    댓글

    • @St é phaneChazelas 정보 감사합니다. ‘ 답변에 expr를 추가했습니다. 용어 ” 배쉬 예 텐션 “는 Bash가 구문을 추가 한 첫 번째 셸이라는 의미가 아닙니다. POSIX sh와 Bash를 배우는 것만으로도 이미 저를 미치게 만들었습니다.
    • man test man [를 시도했지만 길을 잃은 경우. 그것은 POSIX 변형을 설명 할 것입니다.
    • 수정 : ][ 명령에 대한 인수이지만 ‘ t는 추가 인수가 사용되는 것을 방지합니다. ][ 마지막 인수 여야하지만 테스트 표현식의 일부로 발생할 수도 있습니다. 예를 들어 if [ "$foo" = ] ]; then는 변수 foo가 “]

      (if [ ] = "$foo" ]; then도 마찬가지 임).

    • @GordonDavisson 감사합니다. ‘ 모름, 수정되었습니다.
    • @ tgm1024–Monicawasmistreat yes, 그것도 유효한 고려 사항입니다.

    답변

    bash 문서 :

    (list) 목록은 서브 쉘 환경에서 실행됩니다 (아래 명령 실행 환경 참조). 셸의 환경에 영향을주는 변수 할당 및 내장 명령은 명령이 완료된 후에도 유효하지 않습니다. 반환 상태는 목록의 종료 상태입니다.

    즉, “목록”(예 : cd)에서 발생하는 모든 작업이 ( 외부에서 영향을 미치지 않는지 확인합니다. ). 유출되는 유일한 것은 마지막 명령의 종료 코드 또는 set -e 오류를 생성하는 첫 번째 명령 (기타 if, while 등)

    ((expression)) 표현식은 산술 평가에서 아래에 설명 된 규칙에 따라 평가됩니다. 표현식 값이 0이 아니면 반환 상태는 0이고, 그렇지 않으면 반환 상태입니다. 이것은 let ” expression “와 정확히 동일합니다.

    수학을 할 수있는 bash 확장 프로그램입니다. 이는 expr의 모든 제한없이 expr를 사용하는 것과 다소 유사합니다 (예 : 모든 곳에 공백을두고 등)

    [[ expression ]] 다음에 따라 0 또는 1의 상태를 반환합니다. 조건식 표현의 평가. 표현식은 조건식 아래에 설명 된 기본으로 구성됩니다. [[및]] 사이의 단어에는 단어 분할 및 경로 이름 확장이 수행되지 않습니다. 물결표 확장, 매개 변수 및 변수 확장, 산술 확장, 명령 대체, 프로세스 대체 및 따옴표 제거가 수행됩니다. -f와 같은 조건부 연산자는 기본으로 인식 되려면 인용되지 않아야합니다.

    [[, < 및 > 연산자는 현재 로케일을 사용하여 사전 순으로 정렬합니다.

    이는

    제안하지만 더 강력합니다.

    [ expr ] 상태 반환 조건식 expr의 평가에 따라 0 (참) 또는 1 (거짓). 각 연산자와 연산자는 별도의 인수 여야합니다. 표현식은 조건식에서 위에서 설명한 기본으로 구성됩니다. test는 옵션을 허용하지 않으며 옵션의 끝을 나타내는-의 인수를 허용하거나 무시하지 않습니다.

    […]

    이것은 test를 호출합니다. 사실 예전에는 [test에 대한 심볼릭 링크였습니다. 동일한 방식으로 작동하며 동일한 제한이 있습니다. 바이너리는 시작된 이름을 알고 있기 때문에 테스트 프로그램은 시작된시기를 [로 알고 마지막 매개 변수 인 ]. 재미있는 Unix 트릭.

    bash, [test는 (주석에서 언급했듯이) 내장 함수이지만 거의 동일한 제한이 적용됩니다.

    주석

    • 하지만 test[는 물론 Bash의 내장 명령이지만 ‘ 외부 바이너리도 있습니다.
    • [의 외부 바이너리는 대부분의 최신 시스템에서 test에 대한 심볼릭 링크가 아닙니다. .
    • 어쨋든, 두 개의 분리 된 바이너리를 생성해야한다는 점이 흥미 롭습니다. 두 바이너리는 둘 다 결합하고 몇 개의 조건을 추가하는 대신 정확히 필요한 것을 가지고 있습니다. 실제로는 strings /usr/bin/test에도 도움말 텍스트가 표시되어 있지만 ‘ 무슨 말을해야할지 모르겠습니다.
    • @ Random832 예상치 못한 arg0 동작을 피하기위한 GNU 근거에 대한 귀하의 요점을 얻었지만 POSIX 요구 사항에 대해서는 그렇게 긍정하지 않을 것입니다 ‘. 표준에 따라 test 명령은 독립 실행 형 파일 기반 명령으로 존재해야하는 것이 분명하지만, [ 변형이 그렇게 구현해야합니다. 예를 들어 Solaris 11은 ‘ [ 실행 파일을 제공하지 않지만 그럼에도 불구하고 POSIX 표준을 완벽하게 준수합니다.
    • (출구 1)은 괄호 밖에서 효과가 있습니다.

    답변

    몇 가지 예 :

    기존 테스트 :

    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 ... 

    답변

    그룹화 명령

    Bash는 하나의 단위로 실행할 명령 목록을 그룹화하는 두 가지 방법을 제공합니다.

    ( list ) 괄호 사이에 명령 목록을 넣으면 서브 쉘 환경이 생성되고 목록의 각 명령이 해당 서브 쉘에서 실행됩니다. 하위 셸에서 실행되는 경우 변수 할당은 하위 셸이 완료된 후에도 적용되지 않습니다.

    $ a=1; (a=2; echo "inside: a=$a"); echo "outside: a=$a" inside: a=2 outside: a=1 

    { list; } 중괄호 사이의 명령 목록은 현재 쉘 컨텍스트 . 서브 쉘이 작성되지 않습니다. 다음 목록은 세미콜론 (또는 개행)이 필요합니다. 출처

    ${} Parameter expansion Ex: ANIMAL=duck; echo One $ANIMAL, two ${ANIMAL}s $() Command substitution Ex: result=$(COMMAND) $(()) Arithmetic expansion Ex: var=$(( 20 + 5 )) 

    조건부 구성

    단일 브래킷 []
    비교 용 ==, !=, <,>를 사용해야하며 숫자 비교 eq, ne,ltgt를 사용해야합니다.

    향상된 대괄호 [[]]

    위의 모든 예에서 조건식을 묶기 위해 단일 대괄호 만 사용했지만 bash는 단일 대괄호 구문의 향상된 버전 역할을하는 이중 대괄호를 허용합니다.

    비교를 위해 ==, !=, <,>는 문자 그대로 사용할 수 있습니다.

    • [는 테스트 명령의 동의어입니다. 쉘에 내장되어 있어도 새로운 프로세스를 생성합니다.
    • [[는 프로그램이 아니라 키워드 인 새로운 개선 버전입니다. .
    • [[KornBash에서 이해합니다.

    소스

    답글 남기기

    이메일 주소를 발행하지 않을 것입니다. 필수 항목은 *(으)로 표시합니다