이것은 "마치" 규칙입니다.

이것은 "마치" 규칙입니다.

~에서printf가 yash의 내장 부분인지 여부에 대한 질문, 오고 있다이 답변은 POSIX 표준을 참조합니다..

대답은 POSIX 검색 순서가 필요한 명령의 외부 구현을 찾은 다음 쉘이 이를 내장으로 구현한 경우 내장을 실행하는 것이라고 말합니다. (지원되지 않는 내장 기능의 경우특수 내장.)

POSIX에서 내부 구현 실행을 허용하기 전에 외부 구현이 필요한 이유는 무엇입니까?

... 무작위인 것 같아서 궁금했어요.

답변1

이것은 "마치" 규칙입니다.

즉, 구현에서 표준 외부 명령을 쉘 내장으로 제공하기로 결정한 경우 사용자가 보는 쉘의 동작이 변경되어서는 안 됩니다.

제가 보여드린 비교는https://unix.stackexchange.com/a/496291/5132(한편으로는) PD Korn, MirBSD Korn 및 Heirloom Bourne 쉘, (다른 한편으로는) Z, 93 Korn, Bourne Again 및 Debian Almquist 쉘의 동작 사이에서(클래핑 손으로) 이 점을 강조합니다.

printf내장 기능이 없는 쉘 의 경우 호출을 제거하면 작동이 /usr/bin중지됩니다 . 적합 모드에서 Watanabe 쉘이 나타내는 POSIX 적합 동작은 동일한 결과를 가져옵니다. 내장 함수가 있는 쉘의 동작은 다음과 같습니다.PATHprintfprintf마치외부 명령을 호출하는 중입니다.

/usr/bin그러나 모든 자격이 없는 쉘의 동작은 제거되더라도 변경되지 않으며 PATH변경됩니다.아니요외부 명령을 호출하는 것처럼 행동합니다.

표준이 보장하려는 것은 쉘이 모든 종류의 일반적인 외부 명령을 내장할 수 있고(또는 이를 자체 쉘 기능으로 구현할 수 있음) 다음과 같은 경우 내장에서 동일한 동작을 얻을 수 있다는 것입니다. 검색 명령을 방지하도록 조정하면 PATH외부 명령을 사용할 수 있습니다. PATH호출할 수 있는 명령을 선택하고 제어할 수 있는 도구입니다.

(설명대로https://unix.stackexchange.com/a/448799/5132, 몇 년 전, 사람들은 재생되는 내용을 변경하여 Unix의 성격을 선택했습니다 PATH. )

명령을 내리는 것이라고 생각할 수도 있습니다.항상 일하고찾을 수 있는지 여부에 관계없이PATH 사실 그게 요점이야일반적인 외부 명령을 내장합니다. ( printenv사실 이것이 내 nosh 도구 세트에 버전 1.38에 내장 명령이 포함된 이유입니다.아니요지옥처럼. )

하지만 표준에서는 다음을 볼 수 있음을 보장합니다.동일한일반 외부 명령의 동작은 해당 함수를 호출하는 다른 비쉘 프로그램에서 볼 수 있듯이 PATH쉘에서 시작되지 않으며, 쉘은 다른 프로그램이 동일한 명령을 사용하여 찾을 수 없는 일반 외부 명령을 마술처럼 실행하지 않습니다. execvpe()) PATH. 사용자의 관점에서 보면 모든 것이 일관되게 작동하며 PATH작동 방식을 제어하는 ​​도구입니다.

추가 읽기

답변2

이것은 매우 터무니없는 일입니다. 그래서 어떤 쉘도 기본 모드에서 이를 구현하지 않습니다.

표준이유및 설명잘못된 시도였음을 나타냅니다.정기적인경로와 연관된 내장 함수로, 사용자가 경로 앞에 자신만의 바이너리를 표시하여 경로를 재정의할 수 있습니다. PATH예를 들어 printf와 연관된 내장 함수는 외부 명령으로 설정하여 재정의 /usr/bin/printf할 수 있습니다 ./foo/bin/printfPATH=/foo/bin:$PATH

그러나 표준에서는 궁극적으로 이를 요구하지 않고 오히려 요구합니다.다른(또한 쓸모없고 예상치 못한 일이기도 합니다).

여기에서 자세한 내용을 읽을 수 있습니다.오류 보고서. 에서 인용최종 승인된 텍스트:

기존의 많은 구현에서는 PATH 검색을 수행하지 않고 일반 내장 기능을 수행합니다. 이 동작은 사양 텍스트와 일치하지 않으며 스크립트 작성자가 특별히 제작된 PATH를 통해 일반 내장 유틸리티를 재정의하는 것을 허용하지 않습니다. 또한 그 근거는 다음과 같습니다.저자가 취재하는 것이 목적이다. PATH를 수정하여 내장되었지만이것은 규범적인 텍스트가 말하는 것이 아닙니다..

FWIW, 나는 어떤 쉘 구현도 텍스트의 개정된 요구 사항을 수락하지 않았다고 생각합니다.

답변3

후속 비교 echo:printf

(다음과 같은, builtin "특수 내장", "일반 내장"은 쉘에 내장되어 있지 않기 때문에 내장으로 간주되지 않습니다.)

첫 번째 POSIX 표준화 위원회는 에코를 표준화하는 방법에 동의할 수 없었기 때문에 플래그( -e,-n,-E등) 또는 이스케이프 시퀀스( 등)가 포함된 인수가 \n,\c,\t전달되면 동작은 실행 쉘에 의해 결정되고 실행 쉘에 의해 결정되지 않을 것이라고 게시하여 타협했습니다. POSIX로. 대신 printf명령이 추가되고 명확하게 정의된 동작이 제공되었습니다. (출처: Classic Shell Scripting, 작성자: Robbins 및 Beebe)

잘 정의되어 있지만 일부 셸에는 내장 명령이 printf없습니다 (예 : ). 대신 from 을 사용합니다 . 즉, 이 셸에서 실행되는 모든 스크립트는 특정 운영 체제(Ubuntu, Fedora 등)에서 동일한 내용을 인쇄하지만 운영 체제 전체에서 반드시 동일한 내용을 인쇄하지는 않습니다(실제로 많은 사용자가 이유 ).printfmkshprintf/usr/bin/printf/usr/bin

또는 as가 내장된 쉘은 printf운영 체제에 관계없이 동일한 내용을 인쇄하지만 쉘 구현으로 사용되는 경우에만 가능합니다. 그러나 printf동작은 POSIX 표준에 의해 정의되므로 프로그래머는 이에 대해 걱정할 필요가 없습니다. 그러나 from을 사용하는 셸을 PATH재정의하면 찾을 수 없습니다.printf/usr/bin/printf

모든 쉘에는 echo내장 기능이 있지만 일부는 이스케이프 시퀀스를 직접 해석하지만(예: ash) 다른 것(대부분)에는 -e플래그가 필요합니다. 동작은 POSIX가 아니라 쉘에 의해 정의됩니다.

echovs.의 주요 성가심 중 하나 printfecho기본적으로 문자열 끝에 개행 문자를 인쇄하지만 printf그렇지 않다는 것입니다. 새 줄을 인쇄하려면 이스케이프 시퀀스가 printf ​​필요합니다 . 대신, 개행 문자가 인쇄되는 것을 \n방지하려면 이스케이프 시퀀스(및 가능한 경우 flags )가 필요합니다.echo\c-e

printf동작이 POSIX에 의해 정의되므로 최대 이식성을 위해 권장되지만, 개인적으로 각 줄 끝에 개행 문자를 명시적으로 인쇄하는 것이 매우 짜증난다고 생각합니다. (내가 작성한 대부분의 줄은 끝에 개행 문자가 필요하며 억제할 필요가 거의 없습니다. echo새 줄 인쇄). 반면에 echo이는 내장되어 있기 때문에 항상 사용할 수 있으며($PATH에서 찾을 위험이 없음) 간단한 확인을 수행하여 -e플래그가 필요한지 확인하고 해당 별칭을 만들 수 있습니다 echo.

#! /bin/sh -

# Determine if "builtin" command exists.
BUILTIN='builtin'
  
if ! ("${BUILTIN}" echo 123 >/dev/null 2>&1); then
  BUILTIN=''
fi
export BUILTIN

ECHO='echo -e'

if ${BUILTIN} [ "`echo -e test`" = '-e test' ]; then
  ECHO='echo'
fi
export ECHO

# Now use "${ECHO}" where you would normally use "echo"...

개인적으로 나는 이 방법을 선호하며 printf특별한 형식이 필요할 때만 사용합니다.

고쳐 쓰다: 나는 신용이 필요한 곳에 적절한 신용을 제공해야 합니다. 위의 셸 코드는 shunit2Kate Ward 및 shunit2개발팀 에서 직접 가져온 것입니다. (잘하셨어요;) )

답변4

또한 이것을 추가하십시오 (클래식 쉘 스크립트로빈스와 베비엄청난책):

쉘에는 많은 내장 명령이 있습니다. 이는 별도의 프로세스에서 외부 프로그램을 실행하는 것이 아니라 쉘 자체가 명령을 실행한다는 것을 의미합니다. 또한 POSIX는 "특수" 내장 명령과 "일반" 내장 명령을 구별합니다. [대부분의 일반 내장 명령]은 쉘이 제대로 작동하려면 내장되어 있어야 합니다(예 read: ). 효율성을 위해 다른 명령(예: true및 ) 이 셸에 내장되는 경우가 많습니다 false. 또한 이 표준은 효율성을 높이기 위해 추가 명령을 내장할 수 있도록 허용합니다.그러나 모든 일반 내장 기능은 별도의 프로그램으로 액세스할 수 있어야 하며 다른 바이너리 프로그램에서 직접 실행할 수 있어야 합니다.특수 내장 기능과 일반 내장 기능의 차이는 쉘이 실행할 명령을 검색할 때 적용됩니다. 명령 검색 순서는 먼저 특수 내장, 그 다음 쉘 기능, 일반 내장, 마지막으로 검색에 나열된 디렉토리를 통해 찾은 외부 명령입니다 $PATH. 이 검색 순서를 사용하면 일반 쉘 내장 기능을 확장하거나 대체하는 쉘 함수를 정의할 수 있습니다. 이 기능은 대화형 셸에서 가장 일반적으로 사용됩니다. 예를 들어, 쉘의 프롬프트에 현재 디렉토리 경로 이름의 마지막 구성 요소가 포함되기를 원한다고 가정합니다. 이를 달성하는 가장 쉬운 방법은 PS1디렉토리를 변경할 때마다 쉘을 변경하는 것입니다. cd[이를 위해] 자신만의 [] 함수를 작성할 수 있습니다 .연고에 있는 유일한 파리는 여기에 작은 파리가 있다는 것입니다. 쉘 함수는 "실제" 명령의 기능에 어떻게 액세스합니까 cd? ...필요한 것은 쉘에게 함수 검색을 우회하고 실제 명령에 액세스하도록 지시하는 "탈출 해치"입니다. 이것이 command내장 명령의 작업입니다.

[하지만] 이 command명령은 특별한 내장 명령이 아닙니다! 명령이라는 이름의 함수를 정의하는 쉘 프로그래머는 운이 좋지 않습니다! POSIX 표준은 특수 내장 명령에 대해 다음과 같은 두 가지 추가 특수 기능을 제공합니다.

  1. 특수 내장 유틸리티의 구문 오류로 인해 유틸리티를 실행하는 셸이 중단될 수 있는 반면, 일반 내장 유틸리티의 구문 오류로 인해 유틸리티를 실행하는 셸이 중단되어서는 안 됩니다. 구문 오류가 발생한 특수 내장 유틸리티는 쉘을 종료하지 않는 경우 0이 아닌 종료 값을 가져야 합니다.
  2. 특수 내장 유틸리티를 사용하여 지정된 변수 할당은 내장 완료 후에도 유지됩니다. 이는 일반 내장 유틸리티나 기타 유틸리티에서는 발생하지 않습니다. [즉] 명령 앞에 변수 할당을 지정할 수 있으며 변수는 현재 셸이나 후속 명령의 변수에 영향을 주지 않고 명령이 실행되는 환경에서만 해당 값을 갖습니다. (예 PATH=/bin:/usr/bin: awk '...': ) 그러나 이러한 할당을 특수 내장 명령과 함께 사용하는 경우 특수 내장 명령이 완료된 후에도 해당 시점부터 할당이 유효합니다.

아놀드 로빈스와 넬슨 HF 비비. 클래식 쉘 스크립팅: 숨겨진 명령이 Unix의 성능을 발휘합니다(262-5페이지). 오라일리 미디어. 킨들 버전.

command명령을 사용하면 쉘이 지정된 명령과 인수를 간단한 명령으로 처리하므로 쉘 함수 조회가 억제됩니다. ~에서IBM 문서

일반적으로 명령 앞에 /(슬래시)(특정 경로를 나타냄)가 없으면 쉘은 다음 범주를 검색하여 명령을 찾습니다.

특수 쉘 내장 함수 쉘 함수 일반 쉘 내장 함수 PATH 환경 변수 예를 들어 일반 내장 함수와 동일한 이름의 함수가 존재하면 시스템은 해당 함수를 사용하게 된다. 명령 명령을 사용하면 함수와 동일한 이름의 명령을 호출하고 간단한 명령을 얻을 수 있습니다.

-v 명령과 -V 명령은 쉘이 사용할 경로 이름과 쉘이 명령 유형(내장, 함수, 별칭 등)을 해석하는 방법을 표준 출력에 기록합니다. -v 및 -V 플래그는 현재 쉘 환경과 관련된 출력을 생성하므로 이 명령은 Korn 쉘 또는 POSIX 쉘 일반 내장 명령으로 제공됩니다. /usr/bin/command 명령은 서브쉘이나 별도의 명령 실행 환경에서 호출되기 때문에 올바른 결과를 생성하지 못할 수 있습니다. 다음 예에서 쉘은 별칭, 서브루틴 또는 특수 쉘 명령을 인식하지 않습니다.

(PATH=foo 명령 -v) nohup 명령 -v

builtin그래서 이전 예에서는 bash를 대신 사용했습니다. command왜냐하면 bash를 서브셸에 넣으면 작동하지 않기 때문입니다.

나는 @mosvy에 동의합니다. 표준과 사양 텍스트가 일치하지 않는 것 같습니다(정말 말도 안되는 소리입니다).

관련 정보