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


245

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

[[ , [ , ( , ((

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

if [[condition]]

if [condition]

if ((condition))

if (condition)

4
unix.stackexchange.com/questions/tagged/test first 를보고 싶을 수도 있습니다
cuonglm


3
@cuonglm Ironic은 해당 링크가 첫 번째 결과 로이 질문을 생성하기 때문에 역설!
Insane

5
설명서를 읽는 것이 옵션이 아니라고 생각합니까?
궤도에서 가벼움 경주

34
괄호와 대괄호는 문서에서 쉽게 검색 할 수 없으며, 해당 기능의 이름을 모르면 그게 전부입니다.
ilkkachu

답변:


257

if문은 일반적으로 보이는

if commands1
then
   commands2
else
   commands3
fi

then종료 코드 commands1가 0 이면 이 절이 실행됩니다 . 종료 코드가 0이 아닌 경우 else절이 실행됩니다. commands1간단하거나 복잡 할 수 있습니다. 이것은, 예를 들면, 사업자 중 하나에 의해 분리 된 하나 개 이상의 파이프 라인의 순서 일 수있다 ;, &, &&, 또는 ||. if아래 조건은 단지 특별한 경우 commands1:

  1. if [ condition ]

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

  2. if [[ condition ]]

    이것은 bashzsh 도 지원 하는 kshtest 에서 새롭게 업그레이드 된 변형입니다 . 이 명령은 또한 종료 코드를 설정하고 명령문이 그에 따라 작동합니다. 확장 된 기능 중에서 문자열이 정규식과 일치하는지 테스트 할 수 있습니다.testif

  3. if ((condition))

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

  4. if (command)

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

    이와 같이 하부 쉘을 사용하는 일반적인 이유의 부작용을 제한하는 command경우 command변수 할당 또는 셀 환경에 다른 변화를 요구한다. 서브 쉘이 완료된 후에는 이러한 변경 사항이 유지되지 않습니다.

  5. if command

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


24
5 번째 옵션을 포함 해 주셔서 감사합니다. 이것이 실제로 어떻게 작동하는지 이해하고 놀랍게도 활용률이 낮습니다.
병아리

4
그 참고 [실제로 바이너리가 아닌 내부 명령 또는 상징이다. 일반적으로에 살고 있습니다 /bin.
Julien R.

8
@JulienR. 실제로 [는 그대로 내장되어 test있습니다. 호환성을 위해 사용 가능한 이진 버전이 있습니다. help [및을 확인하십시오 help test.
OldTimer

4
((POSIX, $((즉 산술 확장이 [ $((2+2)) -eq 4 ]
아니며

1
이 답변을 두 번 이상 투표 할 수 있기를 바랍니다. 완벽한 설명.
Anthony Gatlin

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

셸에서 모든 명령은 조건부 명령입니다. 모든 명령은 성공을 나타내는 0 또는 실패를 나타내는 1에서 255 사이의 정수 (및 일부 쉘에서는 더 많은 정수)의 반환 상태를 갖습니다. [ … ]명령 (또는 [[ … ]]구 형태)도 철자 수 특정 커맨드 test …및 파일이 존재하는 경우에 성공 또는 문자열은 비어 있지 않은 경우, 또는 경우에 숫자가 다른 것보다 작은 경우에는, 등 ((…))시 구문 형태 성공 다수 0이 아닙니다. 다음은 쉘 스크립트에서 조건의 몇 가지 예입니다.

  • 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 
  • xbash / ksh / zsh에서 (숫자로 간주되는) 값이 2 이상 인지 테스트하십시오 .

    if ((x >= 2)); then 

그 하나의 브라켓이 지원합니다 -a대신를 &&하나 쓸 수 있도록 : [ -L $file -a -f $file ]여분없이 괄호 내에서 같은 수의 문자 인 []...
알렉시스 WILKE

6
연산자를 @AlexisWilke -a-o피연산자 중 일부는 사업자와 같은 모양을 포함하는 경우가 잘못된 구문 분석으로 이어질 수 있기 때문에 문제가있다. 그렇기 때문에 제가 언급하지 않은 이유는 장점이 없으며 항상 작동하지는 않습니다. 그리고 정당한 이유없이 인용되지 않은 변수 확장을 쓰지 마십시오. [[ -L $file -a -f $file ]]괜찮지 만 단일 괄호 [ -L "$file" -a -f "$file" ](예 : $file항상 /또는로 시작하는 경우 ./)가 필요합니다.
Gilles

그것의 유의하십시오 [[ -L $file && -f $file ]](더 -a[[...]]변형).
Stéphane Chazelas

18

로부터 bash는 문서 :

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

다시 말해, 'list'에서 발생하는 모든 일 (예 : a cd)이 (and 외부에 영향을 미치지 않는지 확인하십시오 ). 누출있는 유일한 방법은 마지막 명령 또는 함께 종료 코드입니다 set -e(A와 같은 몇 가지 이외의 오류가 발생 첫 번째 명령 if, while등)

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

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

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

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

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

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

[...]

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

의 경우에는 그 주 bash, [test내장 함수 (코멘트에서 언급 한 바와 같이)이다, 그러나 거의 같은 제한 사항이 적용됩니다.


1
비록 test과는 [물론 배쉬 내장 명령입니다,하지만 외부 바이너리도 존재 가능성이 높습니다.
ilkkachu

1
의 외부 바이너리 [test대부분의 최신 시스템에서 심볼릭 링크가 아닙니다 .
Random832

1
어떻게 든 그들은 두 개의 별도 이진 파일을 만드는 것을 귀찮게합니다. 둘 다 바이너리를 결합하고 몇 가지 조건을 추가하는 대신 필요한 것을 정확히 가지고 있습니다. 실제로 strings /usr/bin/test도움말 텍스트가 있음을 보여 주지만 무엇을 말 해야할지 모르겠습니다.
ilkkachu

2
@ Random832 예기치 않은 arg0 동작을 피하기 위해 GNU의 이론적 근거에 대해 당신의 의견을 얻었지만 POSIX 요구 사항에 관해서는, 나는 긍정적이지 않습니다. 이 test명령은 표준에 의해 독립형 파일 기반 명령으로 존재해야 하지만 분명히 그 [변형을 구현할 필요는 없다. 예를 들어, Solaris 11은 [실행 파일을 제공하지 않지만 POSIX 표준을 완벽하게 준수합니다
jlliagre

2
(출구 1)은 괄호 밖에서 영향을 미칩니다.
Alexander

14

[ vs [[

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

Bash 4.3.11과의 차이점 :

  • POSIX vs Bash 확장 :

  • 정규 명령 대 마법

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

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

      우분투 16.04는 실제로 /usr/bin/[coreutils 가 제공 하는 실행 파일을 가지고 있지만 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 -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' ]]: 따옴표가 필요하지 않습니다.
    • 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?' ]]: 거짓 4 , 마법을 잃는다''
    • [[ ab? =~ 'ab?' ]]: 사실
  • =~

    • [[ 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 쉘 의 동등한 구성에서 영감을 받음

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

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

4 떠들썩한 파티 3.2 이상 및 3.1 날리고 제공 호환성 (와 같이 사용할 수 없습니다 BASH_COMPAT=3.1)

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


정보 감사합니다 @ StéphaneChazelas! expr답변에 추가 했습니다. "Bash extension"이라는 용어는 Bash가 구문을 추가 한 최초의 쉘이라는 것을 의미하지는 않습니다. POSIX sh vs Bash를 배우는 것은 이미 나를 미치게하기에 충분합니다.
Ciro Santilli 新疆 改造 中心 法轮功 六四 事件

man test당신이 시도 man [하고 길을 잃었 는지 확인 하십시오 . POSIX 변형에 대해 설명하겠습니다.
Jonathan Komar

13

몇 가지 예 :

전통적인 시험 :

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

1

그룹화 명령

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는 단일 괄호 구문의 고급 버전으로 사용되는 이중 괄호를 허용합니다.

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

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

출처

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.