wake-up-neo.com

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

Bash (괄호, 이중 괄호, 괄호 및 이중 괄호)에서 사용될 때이 연산자가 다르게 수행하는 작업에 약간 혼란 스럽습니다.

[[ , [ , ( , ((

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

if [[condition]]

if [condition]

if ((condition))

if (condition)
298
RetroCode

if 문은 일반적으로 다음과 같습니다.

if commands1
then
   commands2
else
   commands3
fi

종료 코드 commands1가 0이면 then 절이 실행됩니다. 종료 코드가 0이 아니면 else 절이 실행됩니다. commands1는 간단하거나 복잡 할 수 있습니다. 예를 들어 ;, &, && 또는 || 연산자 중 하나로 구분 된 하나 이상의 파이프 라인 시퀀스 일 수 있습니다. 아래에 표시된 if 조건은 commands1의 특수한 경우입니다.

  1. if [ condition ]

    이것은 전통적인 Shell test 명령입니다. 모든 POSIX 쉘에서 사용 가능합니다. 테스트 명령은 종료 코드를 설정하고 if 문이 그에 따라 작동합니다. 일반적인 테스트는 파일이 존재하는지 또는 하나의 숫자가 다른 숫자와 같은지 여부입니다.

  2. if [[ condition ]]

    이것은 ksh에서 bashzsh도 지원하는 test의 새로운 업그레이드 변형입니다. 이 test 명령은 종료 코드도 설정하며 if 문은 그에 따라 작동합니다. 확장 된 기능 중에서 문자열이 정규식과 일치하는지 테스트 할 수 있습니다.

  3. if ((condition))

    bashzsh도 지원하는 또 다른 ksh 확장. 이것은 산술을 수행합니다. 산술 결과로 종료 코드가 설정되고 if 문이 그에 따라 작동합니다. 산술 계산 결과가 0이 아닌 경우 종료 코드 0을 리턴합니다 (true). [[...]]와 마찬가지로이 양식은 POSIX가 아니므로 이식 할 수 없습니다.

  4. if (command)

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

    이와 같은 서브 쉘을 사용하는 일반적인 이유는 command에 변수 지정 또는 쉘 환경에 대한 다른 변경이 필요한 경우 command의 부작용을 제한하기위한 것입니다. 서브 쉘이 완료된 후에는 이러한 변경 사항이 유지되지 않습니다.

  5. if command

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

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

셸에서 every 명령은 조건부 명령입니다. 모든 명령은 성공을 나타내는 0 또는 1과 255 사이의 정수인 반환 상태를 갖습니다 (및 실패를 나타내는 잠재적으로 더 많은 쉘에서). [ … ] 명령 (또는 [[ … ]] 구문 형식)은 철자 test … 일 수도 있고 파일이 있거나 문자열이 비어 있지 않은 경우에 성공할 수있는 특정 명령입니다. 또는 숫자가 다른 숫자보다 작은 경우 등. 숫자가 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 이상인지 테스트합니다 (이동 가능).

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

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

bash documentation 에서 :

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

다시 말해, 'list'에서 발생하는 모든 일 (예 : cd)이 () 외부에 영향을 미치지 않는지 확인하십시오. 누출 될 유일한 것은 마지막 명령의 종료 코드이거나 오류를 생성하는 첫 번째 명령 인 set -e입니다 (if, while, 기타.)

((expression)) 식은 아래의 산술 평가에 설명 된 규칙에 따라 평가됩니다. 표현식의 값이 0이 아닌 경우 리턴 상태는 0입니다. 그렇지 않으면 리턴 상태는 1입니다. 이것은 "표현식"과 정확히 같습니다.

이것은 수학을 할 수있는 bash 확장입니다. 이것은 expr의 모든 제한없이 expr를 사용하는 것과 다소 비슷합니다 (예 : 어디에나 공백이 있거나 *를 이스케이프하는 등).

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

[[와 함께 사용하면 <및> 연산자는 현재 로케일을 사용하여 사전 식으로 정렬합니다.

이것은 문자열, 숫자 및 파일을 test 오퍼와 약간 비슷하지만 더 강력하게 비교할 수있는 고급 테스트를 제공합니다.

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

[...]

이것은 test를 호출합니다. 실제로 옛날에는 [test에 대한 심볼릭 링크였습니다. 동일한 방식으로 작동하며 동일한 제한이 있습니다. 바이너리는 그것이 시작된 이름을 알고 있기 때문에 테스트 프로그램은 ] 파라미터를 찾을 때까지 파라미터를 구문 분석 할 수 있습니다. 재미있는 유닉스 트릭.

bash의 경우 [test는 내장 함수 (주석에서 언급 한 것처럼)이지만 거의 동일한 제한이 적용됩니다.

20
Alexis Wilke

[ vs [[

이 답변은 질문의 [[[ 부분을 다룹니다.

Bash 4.3.11과의 차이점 :

  • POSIX vs Bash 확장 :

  • 정규 명령 대 마법

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

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

      Ubuntu 16.04는 실제로 coreutils에서 제공하는 /usr/bin/[에 실행 파일이 있지만 bash 내장 버전이 우선합니다.

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

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

    • [[ X ]]X를 마술처럼 파싱하는 단일 구문입니다. <, &&, ||()가 특별하게 취급되며 단어 분리 규칙이 다릅니다.

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

      Bashese에서 : [는 내장 명령이고, [[는 키워드입니다 : https://askubuntu.com/questions/445749/whats-the-difference-between -쉘 내장 및 쉘 키워드

  • <

  • &&||

    • [[ a = a && b = b ]] : true, 논리 and
    • [ 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 상응5
  • 확장시 단어 분할 및 파일 이름 생성 (분할 + 글로브)

    • 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입니다. 현재 디렉토리의 파일로 확장하지 않습니다.
    • [ ab = a? ] : a? glob가 확장됩니다. 따라서 현재 디렉토리의 파일에 따라 true 또는 false 일 수 있습니다.
    • [ ab = a\? ] : false, glob 확장이 아님
    • ===[[[에서 동일하지만 ==는 Bash 확장입니다.
    • case ab in (a?) echo match; esac : POSIX 해당
    • [[ ab =~ 'ab?' ]] : 거짓4''와 함께 마법을 잃습니다!
    • [[ ab? =~ 'ab?' ]] : true
  • =~

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

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

내가 본 모든 [[ ]] 구문마다 POSIX가 있습니다.

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

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

¹ Korn Shell의 동등한 [[...]] 구성에서 영감을 얻었습니다.

² 그러나 a 또는 b의 일부 값 (+ 또는 index과 같은 경우)에 실패하고 ab는 십진 정수처럼 보입니다. expr "x$a" '<' "x$b"는 둘 다 해결합니다.

³ 또한 ! 또는 (와 같은 a 또는 b의 일부 값에도 실패합니다.

4 bash 3.2 이상에서 bash 3.1과의 호환성을 제공하지 않습니다 (BASH_COMPAT=3.1와 같이).

5 {...;}(...) 셸 연산자로 그룹화 (여기서는 || 대신 && 명령 그룹을 사용)가 필요하지 않습니다. (||&&[[...]] 연산자 또는 -o/-a[ 연산자와 달리) 상위. 따라서 [ a = a ] || [ a = b ] && [ a = b ]는 동일합니다.

몇 가지 예 :

전통 테스트 :

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

여러 명령 :

또는 여러 명령을 사용할 수 있습니다. ( ... )에서 명령 세트를 줄 바꿈하면 셸 상태 (작업 디렉토리, 변수)의 temporary 사본을 작성하여 서브 쉘에서 명령을 실행합니다. 다른 디렉토리에서 일부 프로그램을 임시로 실행해야하는 경우 :

# 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 ...
13
ilkkachu

그룹화 명령

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에 의해 이해됩니다.

소스

1
Premraj