Bourne Shell을 배포판에서 사용할 수 없는 경우 hashbang과 함께 /bin/sh를 사용하는 것이 맞습니까?

Bourne Shell을 배포판에서 사용할 수 없는 경우 hashbang과 함께 /bin/sh를 사용하는 것이 맞습니까?

일반적으로 셸 스크립트에는 스크립트 파일의 첫 번째 줄에 다음 주석이 포함됩니다 #!/bin/sh. 내 연구에 따르면 이것은 "해시뱅(hash bang)"이라고 불리며 정기적인 댓글입니다. 이 주석은 파일이 디렉토리의 Bourne Shell에 의해 실행된다는 것을 Unix에 알려줍니다 /bin.

그때부터 내 문제가 시작되었습니다. 지금까지 그런 댓글은 본 적이 없습니다 #!/bin/bash. 언제나 #!/bin/sh. 그러나 Ubuntu 배포판에는 Bourne Shell 프로그램이 없습니다. Bourne Again Shell(bash)이 있습니다.

#!/bin/sh그렇다면 Ubuntu 배포판용으로 작성된 쉘 스크립트에 주석을 넣는 것이 맞습니까 ?

답변1

#!/bin/sh모든 Unix 및 Unix 계열 배포판에서 작동해야 합니다. 스크립트가 POSIX 규격을 준수하는 한 일반적으로 가장 이식성이 뛰어난 해시뱅으로 간주됩니다. 쉘은 쉘로 가장하는 실제 쉘과 /bin/sh관계없이 POSIX 쉘 표준을 구현하는 쉘이어야 합니다 ./bin/sh


#!/bin/sh이제 Bourne 쉘은 더 이상 유지 관리되지 않으므로 일반적으로 링크일 뿐입니다. 많은 Unix 시스템에서는 /bin/sh에 대한 링크가 되고 /bin/ksh, /bin/ash많은 RHEL 기반 Linux 시스템에서는 에 대한 링크가 되지만 /bin/bash, Ubuntu 및 많은 Debian 기반 시스템에서는 에 대한 링크가 됩니다 /bin/dash. 로 호출되면 모든 쉘은 shPOSIX 호환 모드로 들어갑니다 .

hashbang은 스크립트가 엄격하게 POSIX를 준수하는 한(중요성을 강조하기 위해 반복되는) 다른 방법보다 이식성이 높기 때문에 중요한 자리 표시자입니다.

참고: POSIX 모드에서 호출되면 배열 등과 bash같은 POSIX가 아닌 일부 항목은 여전히 ​​허용됩니다. [[이러한 작업은 bash시스템이 아닌 경우 실패할 수 있습니다.

답변2

당신은 그것을 거꾸로 가지고 있습니다. /bin/sh더 이상 Bourne 쉘이 아닙니다. #! /bin/shshe-bang을 사용할 때만 문제가 발생합니다.

Bourne 쉘은 이전 Thompson 쉘(Bourne 쉘이라고도 함)을 대체하여 1970년대 후반에 작성된 쉘입니다 sh. 1980년대 초 David Korn은 Bourne 쉘에 대한 몇 가지 확장을 작성하고 일부 버그와 디자인 어색함을 수정하고(그리고 몇 가지 소개) 이를 Korn 쉘이라고 불렀습니다.

1990년대 초 POSIX는 다음과 같이 명시했습니다.sh 언어/bin/shKorn 쉘의 하위 세트를 기반으로 대부분의 시스템은 이제 Korn 쉘 또는 이 사양을 준수하는 쉘로 변경되었습니다 . BSD의 경우 /bin/sh처음에는(라이선스 문제로 인해 더 이상 Bourne 쉘을 사용할 수 없었음) Almquist 쉘을 점진적으로 변경했습니다. Almquist 쉘은 일부 ksh 확장자를 갖춘 Bourne 쉘의 복제본이므로 POSIX와 호환되었습니다.

오늘날 모든 POSIX 시스템에는 대부분 POSIX와 호환되는 쉘 sh(가장 일반적이지만 /binPOSIX에서는 반드시 그런 것은 아니지만 지정하는 유틸리티에 대한 경로를 지정하지 않음)이 있습니다. 일반적으로 ksh88, ksh93, pdksh, bash, ash 또는 zsh²를 기반으로 하지만 Bourne 쉘은 POSIX와 호환되지 않았기 때문에 Bourne 쉘을 기반으로 하지 않습니다. 이러한 셸 중 일부(, bash및 일부 파생 프로그램은 및 로 호출될 때 POSIX 호환 모드를 활성화합니다.zshyashpdkshsh더 적은그렇지 않으면 규정을 준수합니다).

bash(Korn 셸에 대한 GNU 답변)은 실제로 오픈 소스로 인증된 유일한 것입니다(다른 셸은 일반적으로 90년대 이후 새로운 기능을 받지 못한 ksh88을 기반으로 하기 때문에 현재 유지 관리 중인 경우에만 가능). POSIX 표준 sh(macOS 인증의 일부)

she-bang을 사용하여 스크립트를 작성할 때 #! /bin/sh -표준 구문을 사용해야 합니다 (그리고 이식성을 원한다면 스크립트에 사용되는 유틸리티에 대한 표준 구문도 사용해야 sh합니다. 쉘을 해석할 때는 쉘 스크립트에 관한 것이 아닙니다). sh표준 어떤 구문 해석기 구현이 사용되는지는 중요하지 않습니다( ksh, bash...).

이러한 쉘을 사용하지 않는 한 표준 이상의 확장 기능이 있는지 여부는 중요하지 않습니다. C 코드 작성과 마찬가지로, 표준 C 코드를 작성하고 gcc하나의 컴파일러(예를 들어) 또는 다른 컴파일러에 대한 확장을 사용하지 않는 한, 코드는 컴파일러 구현에 관계없이(컴파일러가 호환되는 한) 괜찮습니다. 보통.

여기에서, #! /bin/sh당신의 주요 문제는 Bourne 쉘이 있는 시스템이 , , ... /bin/sh와 같은 표준 기능을 지원하지 않는다는 것입니다 . 이 경우 다음과 같은 해결 방법이 필요할 수 있습니다.$((1+1))$(cmd)${var#pattern}

#! /bin/sh -
if false ^ true; then
  # in the Bourne shell, ^ is an alias for |, so false ^ true returns
  # true in the Bourne shell and the Bourne shell only.
  # Assume the system is Solaris 10 (older versions are no longer maintained)
  # You would need to adapt if you need to support some other system
  # where /bin/sh is the Bourne shell.
  # We also need to fix $PATH as the other utilities in /bin are
  # also ancient and not POSIX compatible.
  PATH=`/usr/xpg6/bin/getconf PATH`${PATH:+:}$PATH || exit
  export PATH
  exec /usr/xpg4/bin/sh "$0" "$@"
  # that should give us an environment that is mostly  compliant
  # to the Single UNIX Specification version 3 (POSIX.2004), the
  # latest supported by Solaris 10.
fi
# rest of the script

그런데 우분투는 기본값이 /bin/sh아닙니다 . bash현재 dashNetBSD 기반 셸 sh자체는 멀티바이트 문자를 지원하지 않는다는 점을 제외하면 주로 POSIX와 호환되는 Almquist 셸을 기반으로 합니다. Ubuntu 및 기타 Debian 기반 시스템에서는 bash및 ) 4dash 중에서 /bin/sh선택할 수 있습니다 . 데비안과 함께 제공된 스크립트는 데비안 정책 표준(POSIX 표준의 상위 집합)에 따라 작성되었기 때문에 두 셸에서 동일하게 작동해야 합니다. 에뮬레이션에서는 잘 작동한다는 것을 알 수 있습니다 ( 내장 기능이 있을 수도 있고 없을 수도 있습니다(데비안 정책에서는 필요하지만 POSIX에서는 필요하지 않음).dpkg-reconfigure dashshzshshboshksh93yashlocal

unix.stackexchange.com 범위 내의 모든 시스템에는 어딘가에 POSIX가 있습니다 sh . 그들 중 대부분은 하나 /bin/sh(디렉토리가 없는 매우 드문 것을 찾을 수 있지만 /bin아마도 그것에 대해 신경 쓰지 않을 것입니다)와 일반적으로 POSIX sh인터프리터(드물게 (비표준) Bourne 쉘)을 가지고 있습니다.

그러나 sh이것은 시스템에서 찾을 수 있는 유일한 쉘 해석기 실행 파일입니다. 다른 셸의 경우 macOS, Cygwin 및 대부분의 GNU/Linux 배포판에는 bash.SYSV 파생 운영 체제(Solaris, AIX...)가 일반적으로 ksh88 및 ksh93이 있을 수 있습니다. OpenBSD 및 MirOS용 pdksh 파생물이 있을 것입니다. macOS에는 그런 기능이 있을 것입니다 zsh. 하지만 그 이상은 보장할 수 없습니다. bash이러한 다른 쉘이 거기에 설치될 것인지 아니면 다른 곳에 설치될 것인지 보장할 수 없습니다 (예: /bin설치 시 일반적으로 BSD에서 발견됨). /usr/local/bin물론, 설치될 쉘의 버전은 보장되지 않습니다.

#! /path/to/executable그렇지 않으니 참고해주세요관습, 이는 모든 Unix 계열 커널의 기능입니다(1980년대 초반 Dennis Ritchie에 의해 소개됨)로 시작하는 첫 번째 줄에 인터프리터 경로를 지정하여 임의의 파일을 실행할 수 있습니다 #!. 모든 실행 파일이 될 수 있습니다.

첫 번째 줄이 로 시작하는 파일을 실행하면 #! /some/file some-optional-arg커널은 스크립트 경로, 원래 인수를 인수로 /some/file사용 하여 실행을 종료합니다. some-optional-arg첫 번째 줄을 만들어 #! /bin/echo test무슨 일이 일어나고 있는지 확인할 수 있습니다.

$ ./myscript foo
test ./myscript foo

/bin/sh -대신 을 사용하면 /bin/echo test커널은 을 실행하고 /bin/sh - ./myscript foo코드 sh에 저장된 내용을 해석하며 myscript첫 번째 줄은 주석( 로 시작)이므로 무시합니다 #.


오늘날 우리가 접할 수 있는 유일한 /bin/shBourne 쉘 기반 시스템 은 Solaris 10입니다. Solaris는 이전 버전과의 호환성을 위해 Bourne 쉘을 유지하기로 결정한 몇 안되는 Unices 중 하나입니다(POSIX sh언어는 Bourne 쉘과의 이전 버전 호환성을 아직 완전히 구현하지 않음). 그리고 (적어도 데스크탑 및 전체 서버 배포의 경우) sh다른 곳에서( /usr/xpg4/bin/shksh88 기반 ) ) POSIX가 있었지만 Solaris 11에서 변경되었으며 /bin/sh현재는 ksh93입니다. 나머지 대부분은 만료되었습니다.

²MacOS/X는 예전 /bin/shzsh이었지만 나중에 로 변경되었습니다 bash. 주요 초점은 zshPOSIX 구현으로 사용되지 않습니다 sh. 주요 모드 는 sh스크립트에 sourcePOSIX sh코드를 삽입하거나 호출( )할 수 있는 것입니다.zsh

최근에,@힐리OpenSolaris 쉘(SVR4 쉘 기반, Bourne 쉘 기반)을 POSIX 호환 가능하도록 확장했습니다.bosh그러나 나는 아직 어떤 시스템에서도 그것이 사용되고 있다는 것을 알지 못합니다. 이에 더해 ksh88Bourne 쉘 코드를 기반으로 한 두 번째 POSIX 호환 쉘이 됩니다.

4mksh 이전 버전에서는 더 많은 POSIX 버전을 사용할 수도 있습니다 lksh. 이것은 pdksh 기반의 MirOS(이전 MirBSD) 셸이며, 이 셸 자체는 Forsyth 셸(Bourne 셸의 또 다른 재구현)을 기반으로 합니다.

답변3

#!/bin/sh/bin/sh예, 그러한 시스템에서 제공되는 것처럼 (희망적으로) 일반적으로 유언장처럼 동작하게 만드는 일부 연결을 통해 스크립트에서 이를 사용할 수 있습니다 . 예를 들어, 이것은 다음에 연결된 Centos7 시스템입니다.bashshshbash

-bash-4.2$ ls -l /bin/sh
lrwxrwxrwx 1 root root 4 Dec  4 16:48 /bin/sh -> bash
-bash-4.2$ 

이 시스템에 대해서만 스크립트를 작성하고 해당 기능을 사용하려는 경우 #!/bin/bash에도 사용할 수 있습니다 . 그러나 이러한 스크립트는 이식성 문제로 인해 어려움을 겪습니다. 예를 들어 OpenBSD에서는 관리자가 설치하는 데 어려움을 겪은 경우에만 설치됩니다(저는 그렇지 않습니다). 엄격한 POSIX 스크립트는 이식성이 더 높아야 합니다.bashbashbash/usr/local/bin/bash/bin/bash#!/bin/sh

답변4

"#!" 주석은 항상 /bin/bash또는 와 함께 사용되지 않습니다 /bin/sh. 쉘 스크립트뿐만 아니라 인터프리터가 무엇인지 나열합니다. 예를 들어 내 Python 스크립트는 일반적으로 #!/usr/bin/env python.

#!/bin/sh지금과의 차이점은 항상 심볼릭 링크가 아니라는 #!/bin/bash점입니다 . 자주는 아니지만 항상 그런 것은 아닙니다. 우분투는 주목할만한 예외입니다. CentOS에서는 스크립트가 잘 실행되지만 작성자가 bash 특정 구문을 사용했기 때문에 Ubuntu에서는 실패하는 것을 보았습니다 ./bin/sh/bin/bash#!/bin/sh

관련 정보