왜`[`는 쉘 내장이고`[[`는 쉘 키워드입니까?


64

내가 아는 [[한의 향상된 버전 [이지만 [[키워드로 보았을 때 [내장으로 표시 되면 혼란 스럽습니다 .

[root@server ~]# type [
[ is a shell builtin
[root@server ~]# type [[
[[ is a shell keyword

TLDP 는 말합니다

내장은 동일한 이름의 시스템 명령과 동의어 일 수 있지만 Bash는이를 내부적으로 다시 구현합니다. 예를 들어, Bash echo 명령은 동작이 거의 동일하지만 / bin / echo와 동일하지 않습니다.

키워드는 예약어, 토큰 또는 연산자입니다. 키워드는 쉘에 특별한 의미가 있으며 실제로 쉘 구문의 구성 요소입니다. 예를 들어, 동안, 그리고! 키워드입니다. 기본 제공과 유사하게 키워드는 Bash로 하드 코딩되지만 기본 제공과 달리 키워드 자체는 명령이 아니라 명령 구성의 하위 단위입니다. [2]

그것이 키워드 [[[키워드를 모두 만들어서는 안 됩니까? 내가 여기서 놓친 것이 있습니까? 또한, 이 링크 모두 것을 재 - 긍정 [하고 [[동일한 종류에 속하는 것이다.



9
/ bin / [이 내 컴퓨터에 있습니다.
Joshua

2
둘 사이의 한 가지 차이점에 대한 간단한 데모 : if "[" $x -eq 3 ]예상대로 작동하지만 (Bash는라는 명령을 찾음으로써 [존재하지만) 작동 if "[[" $x -eq 3 ]]하지 않습니다 (다시 한번 Bash가 적절한 이름의 명령을 검색하기 때문에 작동 하지 않습니다 ). [[명령).
Kyle Strand

1
@Joshua 그렇게 /usr/bin/echo한다고해서 이것이 내장 된 것이 아님을 의미하지는 않습니다 .
Jonathon Reinhart 6

외부 적으로 존재하는 모든 bulitin은 내장이 아닌 경우 인수를 구문 분석합니다.
Joshua

답변:


80

의 차이 [와는 [[아주 기본입니다.

  • [명령입니다. 인수는 다른 명령 인수가 처리되는 방식으로 처리됩니다. 예를 들어, 다음을 고려하십시오.

    [ -z $name ]

    쉘은 다른 명령과 마찬가지로 결과에서 단어 분리 및 파일 이름 생성을 확장 $name하고 수행 합니다 .

    예를 들어, 다음은 실패합니다.

    $ name="here and there"
    $ [ -n $name ] && echo not empty
    bash: [: too many arguments

    이 작업을 올바르게 수행하려면 따옴표가 필요합니다.

    $ [ -n "$name" ] && echo not empty
    not empty
  • [[쉘 키워드이며 인수는 특수 규칙에 따라 처리됩니다. 예를 들어, 다음을 고려하십시오.

    [[ -z $name ]]

    셸은 확장 $name되지만 다른 명령과 달리 결과에 대해 단어 분할이나 파일 이름 생성을 수행 하지 않습니다. 예를 들어, 공백이 포함되어 있어도 다음이 성공합니다 name.

    $ name="here and there"
    $ [[ -n $name ]] && echo not empty
    not empty

요약

[ 명령이며 쉘이 실행하는 다른 모든 명령과 동일한 규칙이 적용됩니다.

[[그러나 명령은 키워드가 아니기 때문에 쉘은 특수하게 취급하며 매우 다른 규칙에 따라 작동합니다.


+1. 감사. 명령과 키워드가 어떤 규칙에서 작동하는지에 대한 소스 (참조)를 제공 할 수 있습니까?
Tim

@Tim 명령이 작동 하는 규칙 은에 자세히 설명되어 man bash있습니다. 특히 "SIMPLE COMMAND EXPANSION"및 "COMMAND EXECUTION"단원을 참조하십시오. 뿐만 아니라 [[, 다른 배쉬 키워드를 포함 if, then, while,와 '사건'. 키워드에 대한 일반적인 규칙은 없습니다. 각 키워드는 특별한 경우입니다. man bash 각각에 대한 세부 사항을 포함합니다.
John1024

62

Bourne 쉘이 데뷔 한 V7 Unix 에서는 [이라고 test하며로만 존재했습니다 /bin/test. 따라서 오늘 작성하는 코드는 다음과 같습니다.

if [ "$foo" = "bar" ] ; then ...

대신 다음과 같이 작성했을 것입니다.

if test "$foo" = "bar" ; then ...

이 두 번째 표기법은 여전히 ​​존재하며 진행 상황에 대해 더 명확하다는 것을 알았습니다.라는 명령을 호출 test하여 인수를 평가하고 다음에 수행 할 작업을 결정 하는 데 사용 되는 종료 상태 코드 를 반환합니다 if. 이 명령은 셸에 내장되어 있거나 외부 프로그램 일 수 있습니다 .¹

[대안으로하기 test그것은위한 내장 동의어가 될 수 later.²왔다 test, 그러나 또한 제공됩니다 /bin/[내장 명령으로이없는 쉘에 대한 현대적인 시스템.

[test동일한 코드를 사용하여 구현 될 수있다. 이에 대한 경우 /bin/[/bin/test다음은 OS X에 하드 링크 결과 같은 executable.³에, 구현은 완전히 후행를 무시 ]당신이로 호출하는 경우 그것을 필요로하지 않습니다 /bin/[, 그것은 불평하지 않습니다 당신이 경우 어떻게 그것을 제공 /bin/test.⁴

[[라는 원시 프로그램이 없었기 때문에 그 역사에는 영향을 미치지 않습니다 [[. POSIX 쉘 의 확장으로 구현하는 쉘 내부에 존재합니다 .

"내장"과 "키워드"의 차이점 중 일부는이 기록 때문입니다. 또한 구문 분석에 대한 구문 규칙 사실 반영 [[에 지적 표현, 다른 John1024의 답변을 .⁵


각주 :

  1. 이런 식으로 살펴보면 [괄호와 대괄호가 대부분의 다른 프로그래밍 언어에서 작동하는 방식과 달리 왜 쉘 스크립트 에 공백을 넣어야하는지 분명하게 알 수 있습니다. 쉘의 명령 파서가 허용 된 if["$x"...경우에도 허용해야합니다.iftest"$x"...

  2. 1980 년경에 일어났습니다. 1979 년 /bin/[고대 유닉스 V7 사본에는 존재하지 않으며 man test이를 별명으로 문서화 하지도 않습니다 . 필자는 1980 년부터 System III 매뉴얼 의 시험판 사본에있는 해당 맨 페이지 항목 나열되어 있습니다.

  3. ls -i /bin/[ /bin/test

  4. 그러나이 행동에 의존하지 마십시오. 의 강타 내장 된 버전은 [폐쇄를 필요로하지 ], 그리고 내장 된 test당신이 경우 구현은 불평 를 제공합니다.

  5. 내장 된 명령과 외부 명령의 구별 또한 다른 이유로 중요 할 수 있습니다. 두 구현이 다르게 작동 할 수 있습니다. 이것은 echo많은 시스템에서 그렇습니다. 구현은 하나뿐이므로 키워드를 구분할 필요가 없습니다.


당신은 젊은 @Warren 감사하지만, 왜 builtinkeyword구분 사이 [[[모두 (사실을 제외하고 동일한 기능을 제공 할 때 [[더 많은 기능보다는 함께 제공 [)?
Sree

2
@sree [[는 키워드 이므로 bash는 불가능한 일을 할 수 있습니다 [. 즉, 명령 줄 처리는 키워드를 사용할 때 영향을 받지만 내장 명령을 사용할 때는 영향을받지 않습니다.
muru

1
V7 Bourne 쉘 [의 코드는 내장을 표시하지만 코드는 주석 처리되어 있습니다.
Stéphane Chazelas

cd내장되어 있지만 아무것도 가리지 않습니다 ( cd외부 프로그램으로 구현할 수 없음).
Paŭlo Ebermann

2
이것은 훌륭한 역사적 요약이지만 위의 muru와 John1024의 대답에서 지적한 (IMO) 결정적인 세부 사항은 생략 [[합니다. 키워드 를 만들면 쉘이 인수에 대해 특수 파싱 규칙을 사용할 수 있습니다. 따라서 슬프게도, 나의 공감대는 John1024에게 간다.
Ilmari Karonen

3

[원래는 외부 명령으로 다른 이름이었습니다 /bin/test. 그러나 [and와 같은 몇 가지 명령 echo은 쉘 스크립트에서 자주 사용되므로 쉘 구현자는 코드를 사용할 때마다 다른 프로세스를 실행하지 않고 쉘 자체에 직접 코드를 복사하기로 결정했습니다. 전체 경로를 통해 외부 프로그램을 계속 호출 할 수 있지만이 명령은 "내장"으로 바뀌 었습니다.

[[훨씬 나중에왔다. 내장은 셸 내에서 내부적으로 구현되지만 외부 명령과 마찬가지로 구문 분석됩니다. John1024의 답변에서 설명했듯이 인용되지 않은 변수는 단어 분할을 수행하고 토큰 은 I / O 리디렉션 ><같이 처리됩니다. 이로 인해 복잡한 비교 표현식 작성이 불편했습니다. [[쉘 구문으로 만들어 져서 동 기적으로 구문 분석 될 수 있습니다. 내 [[변수 단어 분할을하지 않는, <그리고 >, 비교 연산자로 사용할 수 =등, 다음 매개 변수를 인용 여부에 따라 다르게 동작 할 수 있습니다이하는 모든 편의 시설 있습니다 [[기존보다 사용하기 쉬운 [명령 / 내장이.

[수백만 스크립트에 호환되지 않는 변경이 있었기 때문에 이와 같은 구문으로 간단히 코딩 할 수 없었습니다 . [[이전에는 없었던 새로운 구문 을 사용하여 이전 버전과 호환되는 방식으로 완전히 개선 할 수있었습니다.

이것은 $((...))산술 표현식에 대한 구문을 가져온 진화와 유사하며 대부분 전통적인 expr명령을 대체했습니다 .


0

더 새로운 [[에서이 bash입니다 최적화[.

고전은 [이 사소한 작업을 수행하는 자주 사용되는 경우, 하나의 큰 단점이있다 : 그것은 때마다 새로운 프로세스를 생성합니다 :
(그냥 비교하는 새로운 주소 공간을 생성 0하고 1!마다)

추가의 주요 요점은 [[표현의 평가가 [추가 프로세스를 생성하지 않도록 만드는 것이라고 생각합니다 . 그러나 일이 어떻게 [변할 수 없었는가-많은 혼란과 문제를 야기 할 것입니다. 따라서 최적화는 새로운 이름,보다 효율적인 방식, 즉 쉘 내장 명령으로 구현되었습니다.
쉘 구문에서 키워드로 부작용이되었습니다.

당시 [처음 사용 된 것은 외부 프로세스를 통해 올바른 방법이었습니다 .


5
[원래는 외부 명령 이었지만 Unix System III가 출시 될 때와 Unix System V가 출시되기 전에 쉘에 내장 된 형태로 추가되었습니다. 따라서 '추가 과정'은 오랫동안 문제가되지 않았습니다. 그러나 구문은 변경되지 않은 채 그대로 유지됩니다. 외부 명령 인 것처럼 처리되었습니다.
Jonathan Leffler 2019

@JonathanLeffler 오, 고마워요, [둘 다 보고 싶었습니다. – 그것은 약간의 변화를 의미합니다 ...
Volker Siegel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.