추가 읽기

추가 읽기

#!/bin/sh -eufo pipefail내 스크립트 에 shebang을 넣고 싶습니다 . 하지만 몇 가지 이상한 점이 있습니다.

  1. FreeBSD에서는 이 shebang으로 인해 스크립트가 실패하지만 MacOS에서 실행할 때는 실패하지 않습니다.
  2. /bin/shFreeBSd에서는 명령줄에서 직접 실행할 때 동일한 shebang이 작동합니다(또한 ).
>>> sh -eufo pipefail -c 'echo hi'  # this works
hi

>>> cat <<EOF > script                                                                                      
#!/bin/sh -eufo pipefail
echo hi
EOF

>>> chmod +x ./script 
>>> ./script  # this doesn't work on FreeBSD but works on MacOS
Illegal option -o ./script

>>> cat ./script 
#!/bin/sh -eufo pipefail
echo hi

>>> uname -a
FreeBS 11.3-RELEASE-p7

답변1

#!MacOS는 여전히 2005년 이전의 FreeBSD 동작을 유지합니다. 2005년에는 execve()Linux 및 NetBSD 커널을 포함한 일부 다른 운영 체제 커널과의 일관성을 높이기 위해 FreeBSD 커널이 전달된 실행 파일의 시작 부분을 처리하는 방식이 크게 변경되었습니다 .

NetBSD 커널 소스 코드의 주석은 이를 보편적인 것으로 묘사하려고 시도합니다.

* 쉘 매개변수를 수집합니다. 쉘 이름 뒤의 모든 것
 * 매개변수로 전달되었습니다. 이는 정확합니다(역사적).
 * 행동.
—— kern/exec-script.c. WebBSD. 189행 et seq.

그렇지 않다. Sven Mascheck는 약 10년 전에 몇 가지 테스트를 수행했으며 다음과 같은 결과가 나왔습니다.4개기본 동작 측면에서 AT&T Unix System 5는 4.2BSD와 동일한 "역사적으로 올바른" 동작을 갖습니다.

  • 문자를 무시합니다(4.2BSD 및 AT&T Unix System 5 이전).
  • 단일 인수로 전체 문자열을 전달합니다(2005년부터, 4.2BSD, NetBSD, Linux 및 FreeBSD).
  • 문자열을 공백으로 분할하고 여러 인수로 전달합니다(2005년 이전의 FreeBSD 및 MacOS).
  • 문자열을 공백으로 분할하고 첫 번째 인수만 전달(AT&T Unix System 5 및 Solaris)

이 답변과 관련된 운영 체제만 괄호 안에 포함합니다. M. Mascheck는 FreeBSD 이슈 보고서 16393에 대한 논의에서 Ahmon Dancy가 했던 것처럼 더 많은 것을 확인했습니다. 전체 목록은 추가 자료를 참조하세요.

아이러니하게도 2005년 FreeBSD의 핵심은 FreeBSD가 그렇지 않았다는 것입니다.상당히그렇게 쉽습니다. Perl에 관해 인기 있는 책에 쓰여진 내용이 실제로 작동하도록 고안된 변경 사항이 도입되었습니다. 즉, 주석 문자 다음에 인수를 건너뛰는 것입니다. 이 책에서는 다음을 권장합니다.

#!/bin/sh -- # -*- 펄 -*-
— 래리 월, 톰 크리스티안슨, 존 올원트(2000).Perl을 사용한 프로그래밍: 제3판. 오라일리 미디어. ISBN 9780596000271. 피. 488.

2000년의 PR 16393은 Larry Wall이 말한 방식으로 작성된 실행 가능한 Perl 스크립트를 커널이 처리하도록 하는 방법이었습니다. 그러나 다른 기능이 중단되고 완전히 작동하지 않습니다.

이것에 대해 앞뒤로 이야기가있었습니다. 마지막으로 2005년에 Larry Wall 등의 아이디어를 구현한 메커니즘이 커널 밖으로 옮겨져 Linux, NetBSD 및 4.2BSD(Solaris 및 AT&T Unix System 5는 아님)와 호환되도록 설계되었습니다. 그리고 그것을 리눅스의 책임으로 만들었습니다 sh.

따라서 2005년 이후의 동작은 쉘이 세 개의 인수를 취한다는 것입니다. 두 번째 인수는 #!줄의 전체 꼬리입니다. 스크립트를 직접 호출하는 것은 execve()호출하는 것과 사실상 동일합니다.

sh '-eufo 파이프라인실패' ./script

shAlmquist 쉘( FreeBSD에서)이 이것이 ./script이 옵션에 대한 옵션 매개변수라고 생각하고 해당 부분을 나중에 수집된 추가 한 글자 옵션으로 -o처리하는 이유는 분명합니다 (이 옵션을 얻지 못합니다). 아직 처리되지 않았습니다).pipefail-

또 다른 확실한 대안은 set -o pipefail지적한 대로 스크립트의 첫 번째 명령입니다.https://unix.stackexchange.com/a/533418/5132~을 위한본 패권껍데기. 이것은 FreeBSD에만 추가되었습니다.알름퀴스트그러나 셸은 2019년에 도입되었으므로 최신 버전의 FreeBSD에서만 사용할 수 있습니다. (이것더반2020년 현재 Almquist 쉘은 이를 추가하지 않았습니다. )

추가 읽기

답변2

간단한 것 이상을 사용하기 때문에 사용법 도 #!이식성이 없습니다.

#!/bin/sh

또는 다음과 같이 보편적으로 지원되는 단일 매개변수입니다.

#!/bin/sh -oneflag

진짜 문제는 이식 불가능한 옵션을 사용하고 있다는 것입니다 -o pipefail.

ksh93이는 bash다른 쉘에서는 지원하지 않는 옵션입니다.

배경:

  • MacOS에서는 POSIX와 호환되도록 특정 방식(예: 기본적으로 이스케이프 시퀀스 작동)으로 컴파일됩니다 /bin/sh. bash 지원으로 인해 MacOS에서 작동합니다 (위 참조).bashechopipefail

  • FreeBSD에서는 /bin/sh이것이 ash지원 되지 않습니다 pipefail.

두 가지 가능한 접근 방식이 있습니다.

  • 사용하지 마세요set -o pipefail

  • 2년을 기다렸다가 다시 시도해 보세요. 10개월 전에 이 옵션을 다음 POSIX 표준(문제 8)에 추가하기로 결정했기 때문에 이는 아마도 효과가 있을 것입니다.https://www.austingroupbugs.net/view.php?id=789다음 POSIX 표준은 2019년쯤에 출시될 예정입니다. 지금부터 1년 후에 FreeBSD가 곧 set -o pipefail지원을 추가할 가능성이 높습니다 ash.

관련 정보