Bourne 쉘을 분배에서 사용할 수없는 경우 hashbang에서 / bin / sh를 사용하는 것이 올바른가요?


15

일반적으로 쉘 스크립트는 스크립트 파일의 첫 번째 행에 다음 주석을 포함합니다 #!/bin/sh. 내가 만든 연구에 따르면, 이것을 "해시 뱅 (hash bang)"이라고하며 이는 일반적인 주석입니다. 이 주석은이 파일이 Bourne Shell에 의해 디렉토리 아래에서 실행됨을 Unix에 알립니다 /bin.

내 질문은 그 시점에서 시작됩니다. 지금까지 나는이 의견을 보지 못했다 #!/bin/bash. 항상 그렇습니다 #!/bin/sh. 그러나 우분투 배포판에는 Bourne Shell 프로그램이 없습니다. 그들은 Bourne Again Shell (bash)을 가지고 있습니다.

그 시점 #!/bin/sh에서 우분투 배포본으로 작성된 쉘 스크립트에 주석 을 넣는 것이 맞 습니까?



1
최대의 이식성 을 위해이 serverfault 질문에 대한 나의 답변을 참조하십시오 : #! / bin / sh vs #! / bin / bash .
Gordon Davisson

보다 일반적으로 불림shebang
fpmurphy

답변:


16

#!/bin/sh모든 유닉스와 유닉스 계열 배포판에서 작동합니다. 스크립트가 POSIX를 준수하는 한 일반적으로 가장 휴대용 해시 뱅으로 간주됩니다. /bin/sh쉘에 관계없이 실제 쉘이 아니라 그 무도회 무엇인지, 구현하는 POSIX 표준 쉘하는 쉘 있어야하는데 /bin/sh쉘.


#!/bin/shBourne 쉘이 더 이상 유지 보수되지 않으므로 일반적으로 링크 일뿐입니다. 많은 유닉스 시스템 /bin/sh에서는 링크가 /bin/ksh되거나 /bin/ash많은 RHEL 기반 리눅스 시스템에서는 링크가 /bin/bash되지만 우분투 및 데비안 기반 시스템에서는 링크가됩니다 /bin/dash. 로 호출 된 모든 쉘 sh은 POSIX 호환 모드로 들어갑니다.

해시 뱅은 중요한 자리 표시 자이지만 스크립트가 POSIX를 준수하는 경우 (중요도 중요) 다른 방법보다 이식성이 훨씬 뛰어 나기 때문에 중요한 자리 표시 자입니다.

참고 : bashPOSIX 모드에서 호출 되면 POSIX 이외의 [[배열, 배열 등을 허용합니다. 비 bash시스템 에서는 이러한 일이 실패 할 수 있습니다.


3
"우분투에서는 / bin / dash에 대한 링크"와 일반적으로 다른 데비안 기반 시스템입니다. FreeBSD / GhostBSD의 IIRC도 심볼릭 링크 /bin/ash입니다.
Sergiy Kolodyazhnyy

완전히 휴대하려면 shebang과 (절대) 해석기 경로 사이에 공간을 두십시오. 일부 시스템 #! /은 그냥 대신 찾습니다 #!.
Simon Richter

5
@SimonRichter 이것에 대한 참조는 좋을 것입니다.
Kusalananda

@SergiyKolodyazhnyy FreeBSD에 설치된 sh 버전은 ash이며 심볼릭 링크가 아닙니다.
Rob

2
@Kusalananda, 흠, 이 페이지 는 이것이 신화라고 말하며, 아마도 무시 될 수 있습니다.
Simon Richter

12

당신은 그것을 뒤로했습니다. /bin/sh요즘 Bourne 쉘은 거의 없으며, #! /bin/sh그녀가 뱅뱅 을 사용할 때 문제가 생길 때 ¹입니다 .

Bourne 쉘은 70 년대 후반에 작성된 쉘이며 이전 Thompson 쉘 (이라고도 함 sh)을 대체했습니다 . 80 년대 초 David Korn은 Bourne 쉘에 대한 몇 가지 확장을 작성하고 버그를 수정하고 어색함을 디자인하고 일부를 소개했으며이를 Korn 쉘이라고했습니다.

90 년대 초 POSIX 는 Korn 쉘의 서브 세트를 기반으로 sh 언어 를 지정했으며 대부분의 시스템은 이제 /bin/shKorn 쉘 또는 해당 스펙을 준수하는 쉘로 변경했습니다 . BSD의 경우 /bin/sh, 처음에는 라이센스를 이유로 Bourne 쉘을 더 이상 사용할 수 없게 된 후 점차적으로 변경 되었으며, 일부 ksh 확장자를 가진 Bourne 쉘의 복제 본인 Almquist 쉘은 POSIX 호환이되었습니다.

오늘날 모든 POSIX 시스템 은 대부분 POSIX를 준수 하는 쉘 sh(대부분은 아니지만 /binPOSIX가 지정한 유틸리티의 경로를 지정하지는 않음)을 가지고 있습니다. 일반적으로 ksh88, ksh93, pdksh, bash, ash 또는 zsh²을 기반으로하지만 Bourne 쉘은 POSIX 호환 ³이 아니기 때문에 Bourne 쉘이 아닙니다. 그 껍질의 일부는 ( bash, zsh, yash일부 pdksh로 호출 할 때 파생 상품은 POSIX 호환 모드를 사용 sh하고 있습니다 그렇지 않으면 호환).

bash(Korn 쉘에 대한 GNU 답변)은 실제로 유일한 오픈 소스 쉘이며 다른 하나는 일반적으로 90 년대 이후 새로운 기능을 얻지 못한 ksh88을 기반으로하기 때문에 현재 유지되고 있다고 말할 수 있습니다. POSIX 호환 sh(macOS 인증의 일부).

#! /bin/sh -she-bang 으로 스크립트를 작성할 때 표준 sh구문을 사용해야합니다 (또한 이식성을 원할 경우 해당 스크립트에서 사용되는 유틸리티에 대해 표준 구문을 사용해야합니다. 쉘을 해석 할 때 관련된 쉘만이 아니라) 스크립트), 표준 sh구문 해석기의 구현 이 사용되는 것은 중요하지 않습니다 ( ksh, bash...).

해당 쉘이 사용하지 않는 한 표준에 대한 확장명을 갖는 것은 중요하지 않습니다. 표준 C 코드를 작성하고 하나의 컴파일러 (예 :) gcc또는 다른 컴파일러의 확장자를 사용하지 않는 한 C 코드 작성과 같습니다 . 컴파일러가 호환되는 경우 컴파일러 구현에 관계없이 코드 가 정상적으로 컴파일됩니다.

여기, 당신과 #! /bin/sh그녀 - 쾅, 주요 문제는 시스템이 될 것입니다 /bin/shBourne 쉘입니다 인스턴스를 같은 표준 기능을 지원하지 않습니다에 대한 $((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/shbash기본적으로 아닙니다 . 그건 dash요즘, NetBSD의 기반으로 쉘 sh대부분이 멀티 바이트 문자를 지원하지 않는다는 점을 제외 POSIX를 준수하는 Almquist 쉘에 따라 자체. 우분투와 다른 데비안 기반 시스템에서, 당신은 선택할 수 있습니다 bashdash위해 /bin/shdpkg-reconfigure dash) 4 . sh데비안과 함께 제공되는 스크립트는 데비안 정책 표준 (POSIX 표준의 상위 집합)에 쓰여질 때 두 쉘에서 모두 동일하게 작동해야합니다. 당신은 아마 작업에서 확인 또한을 찾을 수 zshsh에뮬레이션이나 bosh(아마 ksh93yash하지 않는 local데비안 정책이 아닌 POSIX)에 필요한 내장을 ().

unix.stackexchange.com 범위의 모든 시스템에는 POSIX sh 가 있습니다. 그들 대부분은 /bin/sh( /bin디렉토리가 없지만 매우 신경 쓰지 않는 매우 드문 것들을 가지고 있으며 ) 일반적으로 POSIX sh인터프리터 (그리고 드문 경우이지만 (비표준) Bourne 쉘) ).

그러나 sh시스템에서 찾을 수있는 유일한 쉘 인터프리터 실행 파일입니다. 다른 셸의 경우 macOS, Cygwin 및 대부분의 GNU / Linux 배포판에을 포함 할 수 있습니다 bash. SYSV 파생 OS (Solaris, AIX ...)에는 일반적으로 ksh88, 가능하면 ksh93이 있습니다. OpenBSD, MirOS는 pdksh 파생물을 갖습니다. macOS는 zsh. 그러나 그 중에서는 보장 할 수 없습니다. bash다른 쉘이 /bin다른 곳에 설치 될 것인지의 여부는 보증하지 않습니다 ( /usr/local/bin예를 들어 설치 될 때 일반적 으로 BSD 에서 찾을 수 있습니다 ). 물론 설치 될 쉘 버전을 보장하지는 않습니다.

(가) 점에 유의 #! /path/to/executable하지 않은 것입니다 규칙은 , 그것은의 기능의 모든 유닉스 계열 (커널 데니스 리치에 의해 80 년대 초반에 도입 과 함께 첫 번째 줄의 시작에 인터프리터의 경로를 지정하여 임의의 파일을 실행 허용) #!. 모든 실행 파일이 될 수 있습니다.

당신이 그 첫 줄을 시작으로 파일을 실행하면 #! /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 쉘을 유지하기로 결정한 소수의 Unice 중 하나입니다 (POSIX sh언어는 완전하지 않습니다) Bourne 쉘과의 역 호환 가능) (적어도 데스크탑 및 전체 서버 배치의 경우)에는 POSIX가 sh다른 곳에 /usr/xpg4/bin/sh있지만 (ksh88 기반) Solaris 11에서 변경되었으며 /bin/sh현재 ksh93입니다. 다른 것들은 대부분 기능이 없습니다.

² 예전 맥 OS / X의 , 나중에 변경 . POSIX 구현 으로 사용되는 것은 주요 초점 이 아닙니다 . 이 모드는 주로 스크립트에 POSIX 코드 를 포함하거나 호출 할 수 있어야합니다./bin/shzshbashzshshshsourceshzsh

³ 최근 @schily 는 OpenSolaris 쉘 (Bourne 쉘을 기반으로 한 SVR4 쉘 기반)을 POSIX 호환으로 확장 bosh했지만 , 아직 어떤 시스템에서도 사용되고 있다는 것을 알지 못합니다. 이것과 함께 ksh88Bourne 쉘의 코드를 기반으로 두 번째 POSIX 호환 쉘이됩니다.

4 이전 버전에서는 mkshPOSIX lksh화신을 사용 하거나 더 많이 사용할 수도 있습니다 . 이것이 pdksh 기반의 MirOS (이전 MirBSD) 셸이며, 그 자체는 Forsyth 쉘 (본인 쉘의 또 다른 구현)을 기반으로합니다)


(쉘 코드 중반 응답에 대한) 사소한 일 :해야 방금 사용하지 exec sh "$0" "$@"을 설정 한 후 PATH? sh올바른 위치에서 픽업 해야한다고 생각했을 것입니다.
Kusalananda

1
@ Kusalananda, 그것은 작동해야하지만 무언가 잘못되면 무한 루프에 빠질 수 있기 때문에 더 위험합니다 (잘못된 권한이있는 sh, getconf 수정 ...). 어쨌든 나머지는 Solaris 10에만 해당되므로의 내용을 포함하여 모든 것을 하드 코딩 할 수도 있습니다 $PATH.
Stéphane Chazelas

POSIX 쉘로 ksh를 사용하는 OSX에 대한 인용. 그것의 기본 쉘은 tcsh가 될하는 데 사용하지만 OSX가 나온 후까지 Korn 쉘은 오픈 소스가 아니 었로 특히 사용하지 bash는 기억하지 않는다
user151019

1
@ Mark, OSX가 ksh를 사용한다고 말하지 않았습니다. 나는 그것이 zsh 였다고 말했고 그들은 bash (bash의 특별한 빌드)로 전환했다.
Stéphane Chazelas

1
@fpmurphy, 초기 버전을 보면 ksh가 Bourne 쉘과 호환되지 않는 곳에서 bash가 이미 ksh를 사이딩했습니다. bash2가 ksh88과 동일한 기능 수준에 도달하기를 기다려야했지만 bash에는 이미 $(...), emacs / vi 모드, 물결표 / 중괄호 확장 (csh에서 처음으로 하나), fc, typeset, alias 와 같은 몇 가지 ksh 확장이 이미있었습니다. , ksh 스타일 함수 구문 ...
Stéphane Chazelas

8

그렇습니다 . 그러한 시스템에서 (희망적으로) 제공 #!/bin/sh되기 때문에 스크립트에서 사용할 수 있습니다 /bin/sh. 보통은 일종의 링크를 통해 원하는 bash대로 작동합니다 sh. 여기 Centos7 시스템은, 예를 들어, 링크가 shbash:

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

해당 시스템에 대해서만 스크립트를 #!/bin/bash작성하고 기능 bash을 사용하려는 경우 에도 사용할 수 bash있습니다. 그러나 이러한 스크립트는 오픈 BSD에 예를 들어, 이식성 문제를 겪게됩니다 bash관리자가 설치하는 문제가 걸리는 경우에만 설치됩니다 (나는 안) 후가에 설치 /usr/local/bin/bash하지 /bin/bash. POSIX #!/bin/sh스크립트는보다 이식성이 있어야합니다.


"로 호출 sh되면 Bash는 시작 파일을 읽은 후 POSIX 모드로 들어갑니다." - gnu.org/software/bash/manual/bashref.html#Bash-POSIX-Mode
글렌 잭맨

2
직장에서 RHEL 서버용 스크립트를 작성할 때 #!/bin/bashPOSIX 이외의 기능을 활용할 수 있도록 정확하게 사용 합니다.
Monty Harder

RHEL의 @MontyHarder IIRC /bin/sh는 심볼릭 링크 bash입니다. 맞습니까? 그래도 CentOS에 대해서는 알고 있습니다.
Sergiy Kolodyazhnyy

1
@SergiyKolodyazhnyy 예, 방금 확인한 RHEL 서버에서에 대한 심볼릭 링크 bash입니다. 바이너리는 이름을 호출하는 데 사용 된 이름을 알고 있으며, 이름이 불릴 sh때는 구식 Bourne과 같은 역할을 sh합니다.
Monty Harder

6

당신은 물었다

주석 #! / bin / sh를 우분투 배포본으로 작성된 쉘 스크립트에 넣는 것이 맞습니까?

대답은 쉘 스크립트로 작성한 내용에 따라 다릅니다.

  • 이식 가능한 POSIX 호환 스크립트를 엄격하게 사용하고 bash 특정 명령을 사용하지 않으면을 사용할 있습니다 /bin/sh.

  • 당신이 오직 bash에있는 컴퓨터에서 스크립트를 사용하는 것을 알고, 당신은 bash는 특정 구문을 사용하려면, 당신은 해야 사용/bin/bash

  • 확실 스크립트가 유닉스 머신의 구색에 작동합니다되고 싶은 경우에, 당신은 해야 에만 POSIX 호환 구문을 사용하고,/bin/sh

  • 정기적으로 사용하는 경우 다른 쉘 (예 : KSH , zsh을 또는 tcsh의 ), 그리고 스크립트에서이 구문을 사용하려면, 당신은 해야 적절한 통역을 사용 (같은 /bin/ksh93, /bin/zsh또는 /bin/tcsh)


3

"#!" 코멘트는 항상 사용하지 않는 /bin/bash/bin/sh. 쉘 스크립팅뿐만 아니라 인터프리터가해야 할 모든 것을 나열합니다. 예를 들어 내 파이썬 스크립트는 일반적으로로 시작합니다 #!/usr/bin/env python.

지금의 차이 #!/bin/sh와는 #!/bin/bash/bin/sh항상에 심볼릭 링크 아니다 /bin/bash. 항상 그런 것은 아니지만 종종 우분투는 여기서 예외입니다. 필자는 CentOS에서 스크립트가 제대로 작동하지만 작성자가 bash 특정 구문을 사용했기 때문에 Ubuntu에서 실패했습니다 #!/bin/sh.


1

모든 유닉스 시스템에 /bin/sh존재 하는 훌륭한 답변에 찬물을 부어 줘서 미안합니다 . 모든 시간 동안 가장 많이 사용되는 유닉스 시스템을 제외하고는 존재합니다 .Android.

Android에는에 쉘이 있으며 /system/bin/sh, /bin/sh루트 시스템에서도 링크 를 만들 수있는 방법이 없습니다 (selinux 및 capability (7) 경계 세트를 사용하여 시스템을 잠그는 방식 때문에).

안드로이드가 POSIX를 준수하지 않는다고 말하는 사람들에게는 대부분의 Linux 및 BSD 배포가 없습니다. 그리고이 /bin/sh경로 의 존재 는 표준 에 의해 의무화 되지 않습니다 .

애플리케이션은 PATH쉘에 대한 표준 을 /bin/sh또는 로 가정 할 수 없으며 리턴 된 경로 이름이 쉘 내장이 아닌 절대 경로 이름인지 확인 /usr/bin/sh하여 PATH리턴 한 에 대한 질문에 의해 결정되어야합니다 getconf PATH.


POSIX로하려고 모든 시스템 (인증 포함한) 수많은 적합성 버그가 준수하는 동안, 안드로이드 (및 라우터 또는 전구 OS와 같은 대부분의 다른 임베디드 시스템)하지 않는 의도 POSIX를 준수합니다. 안드로이드는 POSIX 인터페이스를 제외하고는 주제가 맞지 않습니다.
Stéphane Chazelas

@ 크리스토퍼 getconf? 예를 들어 Solaris 11.4의 경우 /usr/bin? 하나는 /usr/xpg4/bin(SUSv2 준수), 하나는 /usr/xpg6/bin(SUSv3 준수)? /usr/xpg7/bin(SUSv4 용)?
Stéphane Chazelas

@ StéphaneChazelas 우리가 의도를 판단한다면, 나는 Linus Torvalds 또는 Theo de Raadt 인용문을 POSIX에 대해별로 신경 쓰지 않는 효과에 쉽게 발굴 할 수 있다고 생각합니다 .-) 대부분의 임베디드 시스템은 Linux를 기반으로합니다 + busybox. 일반적인 Unix 계열 시스템보다 POSIX 호환이 적습니다. 그리고) 안드로이드 정말 안드로이드 시스템이 POSIX 호환 할 수있는 "임베디드"시스템 및 b)는하지 않고 있는 쉘을 가진 /bin/sh
mosvy

1
@mosvy, 당신이 말하는 것은 대부분 사실입니다. 그러나 Torvalds는 Linux 커널에 대해서만 말할 수 있습니다. Chet Ramey는 bash에 대한 POSIX 준수, RedHat은 POSIX 준수에 관심이 있습니다 (그들은 Austin 그룹을 후원하고 그룹 회의에 참여하여 많은 GNU 소프트웨어를 유지합니다). 아이디어는 POSIX가 대부분의 유닉스 계열 시스템이 보는 유일한 표준이라는 것입니다. 사용자는 POSIX 규격을 염두에두고 소프트웨어를 다른 시스템으로 쉽게 이식 할 수 있습니다. 이상적이지는 않지만 아무것도 아닌 것보다 낫습니다. Android에는 자체 프로그래밍 API가 있으며 POSIX는 실제로 걱정하지 않습니다.
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.