쉘 스크립트에서 `command` 명령과 `buildin` 명령의 차이점

쉘 스크립트에서 `command` 명령과 `buildin` 명령의 차이점

나는 명령이 command다음에 있다는 것을 안다.최신 POSIX 표준그러나 builtin그것은 진실이 아니다. 나는 또한 두 명령이 모두일반 내장 기능(즉, 사용자 정의 함수로 재정의될 수 있습니다) 일부 쉘에서는 이를 정의 builtin하지만 전부는 아닙니다(예: dash없음). 왜 builtin일부 쉘에 도입되었는지 이해하고 싶습니다 .

내가 아는 한, builtin특수 내장 기능만 반환되고 그 다음에는 일반 내장 기능이 반환되지만 command특수 내장 기능은 반환되고 그 다음에는 일반 내장 기능이 반환되고 그 다음에는 경로의 명령이 반환됩니다(그리고 스위치를 사용하여 이를 지정할 -p수 있습니다 ). command이는 쉘에서 정의한 기본값을 사용합니다( $PATH사용자 수정을 방지하기 위해 $PATH).

예를 들어 mksh다음과 같습니다.

(노트: mkshUbuntu 20.04의 저장소에서 설치됨 http://archive.ubuntu.com/ubuntu focal/universe amd64 mksh amd64 58-1)

$ echo $KSH_VERSION
@(#)MIRBSD KSH R58 2020/03/27
$ which -a echo
/usr/bin/echo
/bin/echo
$ which -a printf
/usr/bin/printf
/bin/printf
$ type echo
echo is a shell builtin
$ type printf
printf is /usr/bin/printf
$ command echo 'Hello World!'
Hello World!
$ command printf 'Hello World!\n'
Hello World!
$ builtin echo 'Hello World!'
Hello World!
$ builtin printf 'Hello World!\n'
mksh: builtin: printf: not found
$ sudo cp /usr/bin/printf /usr/bin/printf.backup
$ sudo cp /bin/printf /bin/printf.backup
$ sudo rm /usr/bin/printf
$ sudo rm /bin/printf
rm: cannot remove '/bin/printf': No such file or directory
$ sudo cp /usr/bin/printf.backup ~/printf
$ echo $PATH | sed 's/:/\n/g'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
# ...remainder ommitted here for brevity
$ export PATH=~:$PATH
$ echo $PATH | sed 's/:/\n/g'
/home/my_username
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
# ...remainder ommitted here for brevity
$ command printf 'Hello World!\n'
Hello World!
$ command -p printf 'Hello World!\n'
mksh: printf: inaccessible or not found

내 이해가 맞나요? 아니면 정확히 같은 일을 command합니까 builtin(만약 그렇다면 왜 builtin도입되었습니까?)? 아니면 command와 사이에 또 ​​다른 미묘한 차이가 있나요 builtin?

(StackExchange에서 답변을 찾아보았지만 아무것도 찾지 못했는데, 혹시 적절한 답변을 알려주시면 정말 감사하겠습니다.)

고쳐 쓰다:

검색을 "건너뛰고" 정의된 별칭을 사용하는 command것도 주목할 가치가 있습니다 . builtinPOSIX 셸 평가 순서에서 별칭 확장은 산술, 변수 및 파일 와일드카드 확장과 마찬가지로 명령 검색 및 평가 앞에 나타납니다. 그러나 산술, 변수 및 와일드카드 command는 sums 내에서 평가되지만 builtin별칭에서는 평가되지 않습니다. 문서에 뭔가 언급되어야 할 것 같습니다.

예를 들어:

$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ command echo $((1 + 1))
2
$ builtin echo $((3 + 1))
4

하지만

$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ alias \[='echo hello'
$ [
hello
$ if builtin [ 'north' != 'south' ]; then echo 'what a world!'; fi
what a world!

업데이트 2:

나는 약간의 조사와 실험 후에 zsh그 행동이완전히 반대POSIX 표준과 기타 Bourne 스타일 셸 및 command명령 간의 관계.

~에서zsh 문서(섹션 6.2, 접두사 명령 수정자)

명령[-pvV]
명령어는 쉘 함수나 내장 명령의 이름이 아닌 외부 명령의 이름으로 처리됩니다.

예를 들어

$ echo ${ZSH_VERSION}
5.8
$ command cd ~
zsh: command not found: cd
$ command -p cd ~
zsh: command not found: cd
$ command echo 'hi'
hi
# `echo` is a regular builtin just like `cd` though...??!!!
$ set -o |grep posix
posixaliases          off
posixargzero          off
posixbuiltins         off
posixcd               off
posixidentifiers      off
posixjobs             off
posixstrings          off
posixtraps            off
$ cd() { echo 'I told you.'; }
$ cd
I told you.
# ????!!!!

이 명령은 POSIX_BUILTINS환경 변수가 설정된 경우에만 ( 를 사용하여) 특수 및 일반 내장 명령을 실행합니다 .set -o posixbuiltinscommand

예를 들어

$ echo ${ZSH_VERSION}
5.8
$ cd /
$ ls
bin   dev  home  lib    lib64   lost+found  mnt  proc  run   snap  sys  usr
boot  etc  init  lib32  libx32  media       opt  root  sbin  srv   tmp  var
$ set -o posixbuiltins
$ command cd ~
$ ls
Desktop    Downloads  Pictures  Templates
Documents  Music      Public    Videos
$ command -p cd /
$ ls
bin   dev  home  lib    lib64   lost+found  mnt  proc  run   snap  sys  usr
boot  etc  init  lib32  libx32  media       opt  root  sbin  srv   tmp  var

반면에,배쉬 문서

주문하다
명령[-pVv]명령[매개변수...]

command라는 셸 함수를 무시하고 인수를 사용하여 명령을 실행합니다. 쉘 내장 명령이나 PATH를 검색하여 찾은 명령만 실행하십시오.

예를 들어

$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>

This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ cd /
$ ls
bin   dev  home  lib    lib64   lost+found  mnt  proc  run   snap  sys  usr
boot  etc  init  lib32  libx32  media       opt  root  sbin  srv   tmp  var
$ set +o posix  # Turn off POSIX mode
$ command cd ~
$ ls
Desktop    Downloads  Pictures  Templates
Documents  Music      Public    Videos
$ command -p cd /
$ ls
bin   dev  home  lib    lib64   lost+found  mnt  proc  run   snap  sys  usr
boot  etc  init  lib32  libx32  media       opt  root  sbin  srv   tmp  var

그래서 zsh행동완전히 반대command다른 Bourne 스타일 명령 쉘에 관해서는 ... zsh점점 싫어지기 시작했습니다... 구매자는 주의하세요(경고 사항) 제 생각에는.

업데이트 3:

내장된 명령이 ksh88없다는 점도 주목할 가치가 있습니다 . command이것은 에서 소개되었습니다 ksh93. 에 내장된 함수를 바꾸려면 ksh88별칭, 함수 및 참조를 어색하게 조합하여 사용해야 합니다.

(출처: Robbins, Arnold; Rosenblatt, Bill. Korn 쉘 학습: Unix 프로그래밍(456페이지). 오라일리 미디어. 킨들 버전.)

이는 @Gilles의 "그래서 악한 행동을 멈추십시오"라는 대답과 일치합니다.

답변1

이것POSIX 정당화command귀하의 질문에 대한 대부분의 역사적 측면에 답변합니다.

이것주문하다8판 쉘과 다소 유사한 유틸리티내장명령을 받았지만 그 이후로주문하다또한 파일 시스템 검색 유틸리티로 이동하여 이름을 지정하십시오.내장직관적이지 않습니다.

(…) 이것주문하다 -V그리고-V이 옵션은 현재 세 가지 다른 기록 유틸리티를 통해 수행되는 사용자 요구 사항을 충족하기 위해 추가되었습니다.유형System V 셸에서는어디KornShell에서어느C 쉘에서.

내부에여덟 번째 판, builtin내장 기능은 우회 기능으로 문서화되어 있습니다.

동일한 이름의 정의된 함수와 상관없이 내장된 특수 명령(예: break)을 실행합니다.

별칭은 아직 존재하지 않습니다(만약 존재하게 되면 별칭을 우회할 수 있는 다른 메커니즘이 있을 것입니다). 외부 명령을 실행하기 위해 함수를 우회하려는 경우 전체 경로를 제공할 수 있습니다. 이는 명령 검색 실행 파일에 해당 이름을 가진 함수가 여러 개 있는 경우 실행하려는 항목을 정확하게 지정할 수 있다는 이점이 있습니다. 명령의 전체 경로가 다를 수 있는 시스템 간 이식성은 일반적인 문제가 아닙니다. builtin실제로 다른 방법으로는 할 수 없는 일도 마찬가지입니다.

나중에 POSIX가 등장하여 기능을 우회하는 표준 방법을 추가했습니다. 이 경우 외부 명령을 다른 위치에 있는 시스템으로 이식하는 것이 큰 문제이므로 builtin충분하지 않습니다. 따라서 새 명령은 command기능( 별칭이 확장되지 않는 위치에 command foo배치된 별칭 포함)을 우회하고 표준 명령을 찾습니다. foo. (현재 ksh에는 완전히 다른 작업을 수행하는 내장 기능이 있지만 builtinPOSIX가 생성되기 전인지 후인지는 알 수 없습니다 command.) 그러나 command내장 기능은 이식성 이유로 의도적으로 건너뛰지 않습니다. if sh 프로그램이 표준 명령을 호출할 때, 운영 체제는 이 명령을 내장 명령으로 제공할지 여부를 선택할 수 있습니다. command응용프로그램이 내장 함수를 호출하는지 여부를 알 필요가 없도록 특수 내장에 대한 "특수 내장" 동작을 다시 억제합니다.

commandPOSIX 모드가 아닐 때 zsh가 내장 기능을 우회하는 이유를 모르겠습니다 (특히 다음과 같은 경우).posix_builtins옵션설정되지 않음). 현재 구현은 command1996년 5월에 발표된 변경 사항으로 거슬러 올라갑니다.zsh 2.6 베타 20("예약어 목록에서 -, exec, noglob 및 명령을 제거합니다."). 구현에서는 이미 POSIX 모드를 다르게 처리하므로 이전 버전의 zsh와의 호환성을 위한 것이라고 가정했지만 더 이상 조사하지 않았습니다. posix_builtins내장 명령이 설정되지 않은 경우 반드시 POSIX와 호환되는 것은 아니므 로 이는 의도적인 것일 수 있습니다 . 따라서 애플리케이션이 특정 POSIX 명령을 사용하는 경우 해당 명령을 호출하지 않는 것이 가장 좋습니다 command.

관련 정보