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

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

나는 명령 command최신 POSIX 표준그렇지 builtin않습니다. 나는 또한 두 명령이 모두일반 내장(즉, 사용자 정의 함수로 덮어쓸 수 있습니다). 일부 쉘은 을 정의 builtin하지만 전부는 아닙니다(예: dash그렇지 않음). 왜 builtin일부 쉘에 도입되었는지 이해하고 싶습니다 .

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

예를 들어 mksh, 다음이 표시됩니다.

(메모: mkshrepo에서 Ubuntu 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또한 이를 언급 하고 builtin정의된 별칭 검색 및 사용을 "건너뛰기"하는 것도 가치가 있습니다 . 별칭 확장은 POSIX 셸 평가 순서에서 산술, 변수 및 파일 와일드카드 확장과 마찬가지로 명령 검색 및 평가보다 먼저 수행됩니다. 그러나 산술, 변수 및 와일드카드는 command및 내에서 평가되지만 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 posixbuiltins) 명령이 command특수 및 일반 내장 기능도 실행합니다.

예를 들어

$ 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행동한다완전한 반대명령 과 관련하여 다른 Bourne 스타일 쉘의 경우 ... 점점 더 command싫어지기 시작했습니다 ...구매자는 주의하세요(zsh주의 사항) 아마도요.

업데이트 3:

내장 명령이 ksh88없다는 점도 주목할 가치가 있습니다 . command이것은 에서 소개되었습니다 ksh93. 내장된 를 대체하려면 ksh88앨리어싱, 함수 및 인용의 어색한 조합을 사용해야 합니다.

(출처: 로빈스, 아놀드; 로젠블라트, 빌. Korn 셸 학습: Unix 프로그래밍(p. 456). 오라일리 미디어. 킨들 에디션.)

이는 @Gilles 'SO- 악한 행동을 중지하세요'의 답변과 일치합니다.

답변1

그만큼POSIX의 이론적 근거command귀하의 질문에 대한 대부분의 역사적 측면에 답변합니다.

그만큼명령유틸리티는 Eighth Edition 쉘과 다소 유사합니다.내장명령을 받았지만 그 이후로명령또한 유틸리티 이름을 검색하기 위해 파일 시스템으로 이동합니다.내장직관적이지 않을 것입니다.

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

에서여덟 번째 판 sh, builtin내장 기능은 함수를 우회하는 것으로 문서화되었습니다.

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

별칭은 아직 존재하지 않았습니다(그리고 별칭이 나타났을 때 이를 우회하는 다른 메커니즘이 있었습니다). 외부 명령을 실행하기 위해 함수를 우회하려는 경우 전체 경로를 제공할 수 있습니다. 이는 명령 검색 경로에 해당 이름을 가진 실행 파일이 여러 개 있는 경우 실행하려는 항목을 정확하게 지정할 수 있다는 이점이 있습니다. 명령의 전체 경로가 다를 수 있는 시스템 간 이식성은 널리 퍼진 문제가 아니었습니다. builtin다른 방법으로는 실제로 수행할 수 없는 일도 마찬가지 였습니다.

나중에 POSIX가 등장하여 함수를 우회하는 표준 방법을 추가했습니다. 이러한 맥락에서 외부 명령이 다른 위치에 있는 시스템으로의 이식성은 매우 우려되는 부분이므로 builtin충분하지 않았습니다. 따라서 command기능(및 별칭이 확장되지 않는 위치에 command foo있기 때문에 별칭)을 우회하고 표준을 찾는 새로운 기능입니다. foo명령. (또한 오늘날 ksh에는 완전히 다른 작업을 수행하는 내장 호출이 있지만 builtinPOSIX 생성 이전인지 이후인지는 알 수 없습니다 command.) 그러나 command이식성 문제로 인해 의도적으로 내장 명령을 건너뛰지 않습니다. sh 프로그램이 표준 명령을 호출하는 경우 이 명령이 내장으로 제공될 수 있는지 여부는 운영 체제에서 선택합니다. command특수 내장 기능의 "특수 내장" 동작을 다시 취소하여 애플리케이션이 내장 기능을 호출하는지 여부를 알 필요가 없도록 합니다.

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

관련 정보