쉘 내장과 쉘 키워드의 차이점은 무엇입니까?


답변:


45

Bash가 코드를 구문 분석하는 방식에서 내장 키워드와 키워드 사이에는 큰 차이가 있습니다. 차이점에 대해 이야기하기 전에 모든 키워드와 내장을 나열하겠습니다.

내장 :

$ compgen -b
.         :         [         alias     bg        bind      break     
builtin   caller    cd        command   compgen   complete  compopt   
continue  declare   dirs      disown    echo      enable    eval      
exec      exit      export    false     fc        fg        getopts   
hash      help      history   jobs      kill      let       local     
logout    mapfile   popd      printf    pushd     pwd       read      
readarray readonly  return    set       shift     shopt     source    
suspend   test      times     trap      true      type      typeset   
ulimit    umask     unalias   unset     wait                          

키워드 :

$ compgen -k
if        then      else      elif      fi        case      
esac      for       select    while     until     do        
done      in        function  time      {         }         
!         [[        ]]        coproc              

예를 들어 [기본 제공 [[키워드 이고 키워드입니다. 잘 알려진 연산자이기 때문에이 두 가지를 사용하여 아래의 차이점을 설명하겠습니다.

Bash는 구문 분석 초기에 키워드를 검색하고 이해합니다. 예를 들면 다음과 같습니다.

string_with_spaces='some spaces here'
if [[ -n $string_with_spaces ]]; then
    echo "The string is non-empty"
fi

이것은 잘 작동하고 Bash는 행복하게 출력합니다.

The string is non-empty

나는 인용하지 않았다 $string_with_spaces. 다음과 같은 반면 :

string_with_spaces='some spaces here'
if [ -n $string_with_spaces ]; then
    echo "The string is non-empty"
fi

Bash가 행복하지 않다는 것을 보여줍니다.

bash: [: too many arguments

내장 키워드가 아닌 키워드로 작동하는 이유는 무엇입니까? Bash가 코드를 구문 분석 할 때 [[키워드가 어떤 키워드인지 확인하고 매우 빠르다는 사실을 이해하기 때문입니다. 따라서 닫힘을 찾고 ]]내부를 특별한 방식으로 처리합니다. 내장 (또는 명령)은 인수와 함께 호출 될 실제 명령으로 취급됩니다. 이 마지막 예에서 bash [는 인수와 함께 명령 을 실행해야한다는 것을 이해합니다 (한 줄에 하나씩 표시됨).

-n
some
spaces
here
]

변수 확장, 따옴표 제거, 경로 이름 확장 및 단어 분할이 발생하기 때문입니다. 이 명령 [은 셸에 내장되어있는 것으로 판명되므로 이러한 인수를 사용하여 명령을 실행하면 오류가 발생하여 불만 사항이 발생합니다.

실제로이 구별은 정교한 동작을 허용하지만 내장 (또는 명령)으로는 불가능한 것을 알 수 있습니다.

아직도 실제로는 어떻게 키워드와 키워드를 구별 할 수 있습니까? 이것은 재미있는 실험입니다.

$ a='['
$ $a -d . ]
$ echo $?
0

Bash가 행을 구문 분석 할 때 $a -d . ]특별한 것은 없습니다 (즉, 별칭, 리디렉션, 키워드 없음). 따라서 변수 확장 만 수행합니다. 변수 확장 후 다음을 볼 수 있습니다.

[ -d . ]

그래서 명령 (내장) 실행 [인수 -d, .그리고 ]사실입니다 물론, (여부를이 단지 테스트 .디렉토리입니다).

이제 봐봐:

$ a='[['
$ $a -d . ]]
bash: [[: command not found

오. Bash 가이 줄을 볼 때 특별한 것은 없으며 모든 변수를 확장하여 결국 다음을 볼 수 있기 때문입니다.

[[ -d . ]]

현재 별칭 확장 및 키워드 검색은 오랫동안 수행되어 더 이상 수행되지 않으므로 Bash는이라는 명령을 찾으려고 찾지 [[못하고 불평합니다.

같은 줄을 따라 :

$ '[' -d . ]
$ echo $?
0
$ '[[' -d . ]]
bash: [[: command not found

$ \[ -d . ]
$ echo $?
0
$ \[[ -d . ]]
bash: [[: command not found

별명 확장도 다소 특별합니다. 모두 다음을 한 번 이상 완료했습니다.

$ alias ll='ls -l'
$ ll
.... <list of files in long format> ....
$ \ll
bash: ll: command not found
$ 'll'
bash: ll: command not found

추론은 동일합니다. 별칭 확장은 변수 확장 및 따옴표 제거 이전에 발생합니다.


키워드 및 별칭

별칭을 키워드로 정의하면 어떻게 될까요?

$ alias mytest='[['
$ mytest -d . ]]
$ echo $?
0

오, 작동합니다! 별칭을 사용하여 키워드의 별칭을 지정할 수 있습니다. 알고 반갑습니다.


결론 : 내장은 실제로 명령처럼 작동합니다. 직접 변수 확장과 단어 분리 및 글 로빙을 수행하는 인수로 실행되는 작업에 해당합니다. 그것은 실제로 어딘가에 외부 명령이 /bin있거나 /usr/bin변수 확장 후에 주어진 인수로 호출되는 것과 같습니다. 내가 말할 때 그것은 실제로 외부 명령을 갖는 것과 같습니다. 나는 인수, 단어 분리, 글 로빙, 변수 확장 등. 내장 함수는 쉘의 내부 상태를 수정할 수 있습니다!

반면에 키워드는 매우 빨리 스캔되고 이해되며 정교한 쉘 동작이 가능합니다. 쉘은 단어 분할 또는 경로 이름 확장 등을 금지 할 수 있습니다.

이제 내장 및 키워드 목록을보고 일부 키워드가 필요한 이유를 알아 봅니다.


!키워드입니다. 함수를 사용하여 동작을 모방하는 것이 가능할 것 같습니다.

not() {
    if "$@"; then
        return false
    else
        return true
    fi
}

그러나 이것은 다음과 같은 구성을 금지합니다.

$ ! ! true
$ echo $?
0

또는

$ ! { true; }
echo $?
1

동일 time: 키워드를 사용하면 복잡한 복합 명령 및 파이프 라인을 재지 정하여 시간을 지정할 수 있습니다.

$ time grep '^#' ~/.bashrc | { i=0; while read -r; do printf '%4d %s\n' "$((++i))" "$REPLY"; done; } > bashrc_numbered 2>/dev/null

경우 time단순한 명령 (심지어 내장이), 그것은 단지 인수를 참조 할 경우 grep, ^#그리고 /home/gniourf/.bashrc, 시간이, 다음의 출력은 파이프 라인의 나머지 부분을 통해 갈 것입니다. 그러나 키워드를 사용하면 Bash가 모든 것을 처리 할 수 ​​있습니다! time경로 재 지정을 포함한 전체 파이프 라인 이 가능 합니다! time단순한 명령 이라면 우리는 할 수 없었습니다.

$ time { printf 'hello '; echo world; }

시도 해봐:

$ \time { printf 'hello '; echo world; }
bash: syntax error near unexpected token `}'

그것을 고치려고 (?)하십시오 :

$ \time { printf 'hello '; echo world;
time: cannot run {: No such file or directory

절망.


키워드 대 별칭?

$ alias mytime=time
$ alias myls=ls
$ mytime myls

당신은 어떻게 생각하십니까?


실제로 내장 은 셸에 내장되어 있다는 점을 제외하고는 명령과 비슷하지만 키워드 는 정교한 동작을 허용하는 것입니다! 우리는 그것이 셸 문법의 일부라고 말할 수 있습니다.


2
@JohnyTex와 동의 한 이것은 스택 사이트에서 본 가장 포괄적이고 적절한 답변 중 하나입니다. 고맙습니다. 아마도 관련이없는 질문 중 하나입니다 : 호기심을 위해서 ,, =\을 사용하여 명령 앞에 ''일시적으로 별칭 비활성화 '기능에 대한 설명서를 찾으려고 노력 하고 있으며 운이 없었습니다. 이 정보를 어디에서 찾을 수 있을까요? 나중에 참조 소스가 누락되었다고 생각하기 때문에 앞으로는 다른 내용을 볼 수 있습니다. manaproposhelp
nc.

@nc : 명시 적으로 문서화되어 있지 않습니다. 그것이 작동하는 이유는이 답변에 설명되어 있습니다. 가장 가까운 것은 Shell Operation 섹션의 참조 매뉴얼에 있습니다. 2 단계에서 별칭 확장이 매우 일찍 (이 답변에서 강조하려고 한 것 ) 수행되었음을 알 수 있습니다 . 따옴표 제거, 매개 변수 확장, 글 로빙 등은 나중에 수행됩니다. 그래서 할 비활성화 별칭을, 당신을 인용의 어떤 종류를 사용할 수 있습니다 금지 별칭으로 토큰을 이해하고, 예를 들어,에서 쉘을 \ll, "ll"또는 'll'.
gniourf_gniourf

1
실제로 주문, 별칭 및 키워드가 먼저 발생했습니다. 우리는 [[수확량 을 인용하므로 \[[별칭으로 구문 분석되지 않습니다. 지금까지? 내가 잃어버린 곳에서 백 슬래시가 Bash의 인용문이라는 것을 깨닫지 못했고 별칭과 키워드로 찾아보고 완전히 잃어 버렸습니다. 인용 섹션에서 :> 따옴표없는 백 슬래시 ()는 이스케이프 문자입니다.
nc.

1
따라서 우리는 Op 목록에서 (2)를 \[[토큰 화로 생각할 수 있으며, OpenTestKeywordToken과는 반대로 LiteralQuoteToken 유형의 단일 토큰 이며 oroper 컴파일 / 올바른 구문 [[을 위해서는 ]]CloseCloseKeyKeyToken을 닫아야합니다. 나중에 (4)에서 LiteralQuoteToken은 [[실행할 bulitin / command의 이름 으로 평가 되며 (6) [[내장 또는 명령 이 없으므로 Bash는 barf 입니다. 좋은. 시간이 지남에 따라 정확한 세부 사항을 잊어 버릴 수 있지만 현재 Bash가 작업을 수행하는 방식이 훨씬 명확합니다. 고맙습니다.
nc.

9

man bash그들을 호출합니다 SHELL BUILTIN COMMANDS. 따라서 "shell builtin"은 일반적인 명령 (예 grep: 등)과 비슷하지만 별도의 파일에 포함되지 않고 bash 자체에 내장되어 있습니다 . 이것은 외부 명령보다 더 효율적으로 수행합니다.

키워드는 또한 "강타로 하드 코딩하지만, 내장 달리 키워드는 그 자체로는 명령이 아니라 명령 구조의 서브 유닛"입니다. 키워드 자체로는 기능이 없지만 어떤 작업을 수행하려면 명령이 필요하다는 것을 의미합니다. (링크에서 다른 예는 for, while, do,과 !, 그리고 거기에 더에 내 대답은 다른 질문에.)


1
흥미로운 사실 ​​: [[ is a shell keyword하지만 [ is a shell builtin. 왜 그런지 모르겠습니다.
Sparhawk

1
역사적 이유로 POSIX 표준은 이전 Bourne 쉘을 가능한 한 가깝게 준수 할 가능성이 높습니다 [. [[표준에 의해 지정되지 않으므로 개발자는 해당 키워드를 키워드 또는 내장으로 포함하도록 선택할 수 있습니다.
Sergiy Kolodyazhnyy

1

Ubuntu와 함께 제공되는 명령 줄 설명서는 키워드에 대한 정의를 제공하지 않지만 온라인 설명서 (부록 참조) 및 POSIX Shell Command Language 표준 사양 은 "예약어"라고하며 둘 다 해당 목록을 제공합니다. POSIX 표준에서 :

이 인식은 문자를 인용하지 않고 단어를 다음과 같이 사용하는 경우에만 발생합니다.

  • 명령의 첫 단어

  • case, for 또는 in 이외의 예약어 중 하나를 따르는 첫 번째 단어

  • case 명령의 세 번째 단어 (이 경우에만 유효)

  • for 명령의 세 번째 단어 (이 경우에만 및 do가 유효 함)

여기서 핵심은 키워드 / 예약어는 쉘 구문을 용이하게하고 루프, 복합 명령, 분기 (if / case) 명령문 등과 같은 특정 코드 블록을 신호하는 역할을하기 때문에 특별한 의미를 갖습니다. 스스로 - 아무것도하지 않으며, 사실 당신과 같은 키워드를 입력하면 for, until, case- 쉘이 완전한 그렇지 않으면 문, 기대 - 구문 오류 :

$ for
bash: syntax error near unexpected token `newline'
$  

소스 코드 레벨에서 bash의 예약어는 parese.y에 정의되어 있지만 내장 디렉토리에는 전용 디렉토리 가 있습니다.

사이드 노트

GNU 인덱스는 [예약어로 표시 되지만 사실상 기본 제공 명령입니다. [[반대로 예약어입니다.

키워드, 예약어 및 내장 단어의 차이점 도 참조하십시오 .

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