원문 보기: https://dawoum.duckdns.org/wiki/Shebang_(Unix)
컴퓨팅에서. 셔뱅(shebang)은 스크립트 시작 부분에 있는 숫자 기호 (샤프(sharp) 또는 해시(hash)라고도 함)와 느낌표 (뱅(bang)이라고도 함)로 구성된 문자 순서열 #!입니다. 그것은 역시 샤프-느낌표(sharp-exclamation), 샤-뱅(sha-bang), 해시뱅(hashbang), 파운드-뱅(pound-bang), 또는 해시-플링(hash-pling)이라고도 합니다.
셔뱅을 갖는 텍스트 파일이 유닉스-계열 운영 시스템에서 실행 파일인 것처럼 사용될 때, 프로그램 로더 메커니즘은 파일의 시작 줄의 나머지 부분을 인터프리터 지시문으로 구문 분석합니다. 로더는 지정된 인터프리터 프로그램을 실행하고, 스크립트를 실행하려고 할 때 처음 사용된 경로를 인수로 전달하여, 프로그램이 해당 파일을 입력 데이터로 사용할 수 있도록 합니다. 예를 들어, 만약 스크립트의 이름이 path path/to/script 경로로 지정되고, #!/bin/sh 줄로 시작하면, 프로그램 로더는 path/to/script를 첫 번째 인수로 전달하여 프로그램 /bin/sh를 실행하라는 지시를 받습니다.
셔뱅 줄은 보통 인터프리터에 의해 무시되는데, 왜냐하면 "#" 문자가 많은 스크립팅 언어에서 주석 표시기이기 때문입니다; 주석을 시작하기 위해 해시 표시를 사용하지 않는 일부 언어 인터프리터는 여전히 셔뱅 줄의 목적을 인식하고 이를 무시할 수 있습니다.
Syntax
셔뱅 인터프리터 지시문의 형식은 다음과 같습니다:
#!interpreter [optional-arg]
이것에서 interpreter는 실행-가능 프로그램으로 경로입니다. #!와 interpreter 사이의 공백은 선택 사항입니다. interpreter 앞이나 뒤에는 아무리 많은 공백이나 탭이 있어도 됩니다. optional-arg에는 줄 끝까지의 임의의 여분의 공백이 포함됩니다.
Linux에서, interpreter에 의해 지정된 파일은 만약 그것이 실행 권한이 있고 다음 중 하나이면 실행될 수 있습니다:
- ELF 바이너리와 같은 네이티브 실행 파일
- binfmt_misc 메커니즘을 통해 인터프리터가 등록된 임의의 종류의 파일 (예를 들어, wine을 사용하여 Microsoft .exe 바이너리를 실행하는 경우)
- 셔뱅으로 시작하는 또 다른 스크립트
Linux와 Minix에서, 인터프리터는 스크립트가 될 수도 있습니다. 셔뱅과 래퍼의 체인은 마주친 스크립트를 역순으로 매개변수로 가져오는 직접 실행 가능한 파일을 생성합니다. 예를 들어, 파일 /bin/A가 ELF 형식의 실행 파일이고, 파일 /bin/B가 셔뱅 #!/bin/A optparam을 포함하고, 파일 /bin/C가 셔뱅 #!/bin/B를 포함하면, 파일 /bin/C를 실행하는 것은 /bin/B /bin/C로 해석되며, 이는 최종적으로 /bin/A optparam /bin/B /bin/C로 해석됩니다.
Solaris-파생된 및 Darwin-파생된 운영 시스템 (예를 들어, macOS)에서, 인터프리터에서 지정된 파일은 실행 가능한 바이너리여야 하고 그 자체가 스크립트가 될 수는 없습니다.
Examples
일부 전형적인 셔뱅 줄:
- #!/bin/sh – /bin 디렉토리에 있는 것으로 가정되는 Bourne shell, 또는 호환 쉘을 사용하여 파일을 실행
- #!/bin/bash – Bash shell을 사용하여 파일을 실행
- #!/usr/bin/pwsh – PowerShell을 사용하여 파일을 실행
- #!/usr/bin/env python3 – python3을 찾기 위해 env 프로그램 찾기 경로를 사용하여 Python 인터프리터로 실행
- #!/bin/false – 아무것도 하지 않지만, 실패를 나타내는 비-영 종료 상태를 반환. sh/bash의 . 명령, csh/tcsh의 source, 또는 .profile, .cshrc, 또는 .login 파일과 같이 특정 컨텍스트에서 실행되도록 의도된 스크립트 파일의 독립 실행을 방지하기 위해 사용됩니다.
셔뱅 줄에는 인터프리터에 전달되는 특정 옵션이 포함될 수 있습니다. 어쨌든, 구현은 옵션의 구문 분석 동작에 따라 다릅니다; 이식성을 위해, 포함된 공백 없이 하나의 옵션만 지정해야 합니다. 추가 이식성 지침은 아래에서 찾을 수 있습니다.
Purpose
인터프리터 지시어는 스크립트와 데이터 파일을 명령으로 사용되도록 허용하며, 명령줄에서 스크립트 앞에 인터프리터를 접두사로 붙일 필요성을 제거함으로써 사용자와 다른 프로그램에서 구현 세부 정보를 숨길 수 있습니다.
예를 들어, 첫 줄 #!/bin/sh -x를 갖는 스크립트를 생각해 보십시오. 그것은 some/path/to/foo와 같은 파일 경로와 bar 및 baz와 같은 일부 매개변수를 제공함으로써 간단히 호출될 수 있습니다:
some/path/to/foo bar baz
이 경우에서, 원래 명령이 아래에 나와 있는 것처럼, 매개변수 -x, some/path/to/foo, bar, and baz를 갖는 /bin/sh가 대신 호출 그 자리에 호출됩니다:
/bin/sh -x some/path/to/foo bar baz
대부분의 인터프리터는 스크립트에 임의의 추가적인 인수를 제공합니다. 만약 /bin/sh가 POSIX-호환 쉘이면, bar와 baz는 위치 매개변수 배열 "$@"로 스크립트에 표시되고, 각각 매개변수 "$1"과 "$2"로 표시됩니다.
초기 #은 POSIX 쉘 언어 (및 다른 많은 인터프리터에 의해 이해되는 언어)에서 주석을 도입하기 위해 사용되는 문자이기 때문에, 인터프리터에 의해 전체 셔뱅 줄이 무시됩니다. 어쨌든, 셔뱅 줄을 무시하는 것은 인터프리터의 몫이고, 모든 인터프리터가 그렇게 하는 것은 아닙니다; 따라서, 다음 두 줄로 구성된 스크립트는 실행 시 두 줄을 모두 출력합니다:
#!/bin/cat
Hello world!
Strengths
파일 확장자와 해석 응용 프로그램 사이의 전역적 결합 목록의 사용과 비교했을 때, 해석기 지시문 방법은 사용자에게 전역적 시스템 수준에서 알려지지 않은 해석기를 관리자 권한 없이 사용하는 것을 허용합니다. 그것은 역시 파일 이름 확장자 이름공간 (한 파일 확장자가 두 개 이상의 파일 유형을 참조하는 경우)을 오버로드 없이 해석기의 구체적 선택을 허용하고, 다른 프로그램에 의해 호출 구문을 변경 없이 스크립트의 구현 언어를 변경하도록 허용합니다. 스크립트 호출자는 스크립트 자체가 사용할 해석기를 지정해야 하므로 구현 언어가 무엇인지 알 필요가 없습니다.
Portability
Program location
셔뱅은 시스템 실행 파일에 대한 절대 경로 (또는 현재 작업 디렉토리에 대한 상대 경로)를 지정해야 합니다; 이것은 비-표준 파일 시스템 레이아웃을 가지는 시스템에서 문제를 일으킬 수 있습니다. 심지어 시스템이 상당히 표준적인 경로를 가질 때 조차도, 같은 운영 시스템의 변형에서 원하는 인터프리터에 대한 위치가 다를 수 있습니다. 예를 들어, Python은 /usr/bin/python3, /usr/local/bin/python3,, 또는 심지어 일반 사용자에 의해 설치되면 /home/username/bin/python3과 같은 위치에 있을 수 있습니다.
비슷한 문제는 POSIX 쉘에도 존재하는데, 왜냐하면 POSIX는 이름만 sh로 요구하지만, 경로를 지정하지 않았기 때문입니다. 공통적인 값은 /bin/sh이지만, Solaris와 같은 일부 시스템은 /usr/xpg4/bin/sh에 POSIX-호환 쉘을 가지고 있습니다. 많은 Linux 시스템에서, /bin/sh는 ourne Again shell (BASH), /bin/bash에 대한 하드 링크 또는 심볼릭 링크입니다. sh를 가리키는 셔뱅을 유지하면서 bash-특정 구문을 사용하는 것도 이식성이 없습니다.
이것 때문에, 때때로 스크립트를 한 컴퓨터에서 다른 컴퓨터로 복사한 후에 셔뱅 줄을 편집해야 하는데, 왜냐하면 스크립트에 코딩된 경로가 인터프리터 배치의 과거 규칙에서 일관성에 의존하는 새 컴퓨터에 적용되지 않을 수 있기 때문입니다. 이러한 이유와 POSIX가 경로 이름을 표준화하지 않기 때문에, POSIX는 이 기능을 표준화하지 않습니다. GNU Autoconf 도구는 매크로 AC_SYS_INTERPRETER를 갖는 시스템 지원에 대해 테스트할 수 있습니다.
종종, 프로그램 /usr/bin/env는 간접성의 수준을 도입함으로써 이러한 제한을 우회하기 위해 사용될 수 있습니다. #! 뒤에 /usr/bin/env가 오고, 그 뒤에 전체 경로 없이 원하는 명령이 옵니다, (다음 예제에서처럼):
#!/usr/bin/env sh
이것은 대부분 작동하는데 왜냐하면 경로 /usr/bin/env는 공통적으로 env 유틸리티에 대해 사용되고, 그것은 사용자의 $PATH에서 발견된 첫 번째 sh, 전형적으로 /bin/sh를 호출하기 때문입니다.
이 특정 예제 (sh 사용)는 유용성이 제한적입니다: /bin/sh도 /usr/bin/env도 보편적이지 않으며, 비슷한 수의 장치에 각각이 없습니다. 더 광범위하게, 임의의 스크립트에 #!/usr/bin/env를 사용하는 것은 여전히 OpenServer 5.0.6 및 Unicos와 일부 이식성 문제가 있으며, 이들에는 /bin/env만 있고 /usr/bin/env는 없습니다.
#!/usr/bin/env를 사용하는 것은 런-타임 간접 참조가 발생하여, 시스템 보안이 저하될 가능성이 있습니다; 이러한 이유로, 일부 해설자는 패키지 소프트웨어에서 이를 사용하지 말 것을 권장하며, "교육적 예"로만 사용할 것을 권장합니다.
Character interpretation
또 다른 이식성 문제는 명령 인수의 해석입니다. 리눅스를 포함한 일부 시스템은 인수를 분리하지 않습니다; 예를 들어, 첫 번째 줄로 스크립트를 실행할 때,
#!/usr/bin/env python3 -c
첫 번째 공백 뒤의 모든 텍스트는 단일 인수로 처리되며, 즉, python3 -c는 두 개의 인수가 아닌 하나의 인수로 /usr/bin/env에 전달됩니다. Cygwin도 이런 방식으로 동작합니다.
복잡한 인터프리터 호출은 추가적인 래퍼의 사용을 통해 가능합니다. FreeBSD 6.0 (2005)은 shebang-reading 동작을 분할하지 않는 것으로 변경하면서 env에 -S 옵션을 도입했습니다. 이 옵션은 env에 문자열 자체를 분할하도록 지시합니다. coreutils 8.30 (2018) 이후의 GNU env 유틸리티에도 이 기능이 포함되어 있습니다. 비록 이 옵션을 사용하는 것이 분할과 관련된 커널 측의 이식성 문제를 완화하지만, 그것은 env가 이 특정 확장을 지원해야 한다는 요구 사항을 추가합니다.
또 다른 문제는 셔뱅 줄 바로 뒤에 캐리지 리턴 문자를 포함하는 스크립트이며, 이는 Microsoft Windows와 같이 DOS 줄 바꿈을 사용하는 시스템에서 편집된 결과일 수 있습니다. 일부 시스템은 캐리지 리턴 문자를 인터프리터 명령의 일부로 해석하여, 오류 메시지를 생성합니다.
Magic number
셔뱅은 실제로 실행 파일에서 사람이 읽을 수 있는 매직 넘버의 인스턴스이며, 매직 바이트 문자열은 0x23 0x21이고, ASCII로 2자리 인코딩된 #!입니다. 이 매직 넘버는 파일이 스크립트인지 실행 가능한 바이너리인지 판별하는 "exec" 함수의 가족에 의해 감지됩니다. 셔뱅의 존재는 지정된 실행 파일, 보통 스크립트 언어의 인터프리터의 실행을 초래할 것입니다. 일부 오래된 버전의 유닉스에서는 통상의 셔뱅 뒤에 공백과 슬래시 (#! /)가 와야 한다고 주장되었지만, 이는 사실이 아닌 것으로 보입니다; 오히려, 셔뱅 뒤의 공백은 전통적으로 허용되어 왔고, 때로는 아래의 1980년 역사적 이메일에서 설명한 대로 공백과 함께 문서화되었습니다.
셔뱅 문자는 UTF-8을 포함한 확장 ASCII 인코딩에서 같은 두 바이트에 의해 표현되며, 이는 현재 유닉스-계열 시스템에서 스크립트 및 기타 텍스트 파일에 공통적으로 사용됩니다. 어쨌든, UTF-8 파일은 선택적인 바이트 순서 표시 (BOM)로 시작할 수 있습니다; 만약 "exec" 함수가 특별히 바이트 0x23과 0x21을 감지하면, 셔뱅 앞에 BOM (0xEF 0xBB 0xBF)의 존재는 실행되려는 스크립트 인터프리터를 막을 것입니다. 일부 기관에서는 이러한 이유와 더 광범위한 상호 운용성 및 철학적 우려로 인해 POSIX (유닉스-계열) 스크립트에서 바이트 순서 표시를 사용하지 말 것을 권장합니다. 추가적으로, UTF-8에서 바이트 순서 표시가 필요하지 않는데, 왜냐하면 이 인코딩에는 엔디안 문제가 없기 때문입니다; 그것은 인코딩을 UTF-8로 식별하는 데만 사용됩니다.
Etymology
인터프리터 지시어로 시작하는 실행 파일은 간단히 스크립트라고 불리며, 종종 의도된 인터프리터의 이름이나 일반적인 분류로 시작합니다. 이 두 가지 독특한 문자에 대한 이름 셔뱅은 SHArp bang 또는 haSH bang의 부정확한 축약에서 유래했을 수 있으며, 그것들에 대해 두 가지 전형적인 유닉스 이름을 나타냅니다. 셔뱅에서의 sh에 대한 또 다른 이론은 보통 셔뱅으로 호출되는 기본 쉘 sh에서 유래했다는 것입니다. 이 사용법은 1989년 12월까지 유효했고, 아마도 그보다 더 이전일 것입니다.
History
셔뱅은 벨 연구소의 Edition 7과 8 사이에 DDennis Ritchie에 의해 도입되었습니다. 그것은 역시 Berkeley의 Computer Science Research (2.8BSD에 존재하고 4.2BSD에서 기본적으로 활성화됨)의 BSD 릴리스에도 추가되었습니다. AT&T Bell Laboratories Edition 8 Unix와 이후 에디션은 대중에게 공개되지 않았기 때문에, 이 기능이 널리 알려진 첫 번째 모습은 BSD에 있었습니다.
인터프리터 지시어가 없지만, 쉘 스크립트에 대한 지원은 1979년 버전 7 Unix의 설명서에서 명백하게 드러났으며, 이 설명서에서는 대신 Bourne 쉘의 기능에 대해 설명하며 여기서 실행 권한을 갖는 파일은 쉘에서 특별히 처리됩니다. 쉘은 (때로는 스크립트의 ":" 또는 "#"과 같은 초기 문자에 따라) 파일에 포함된 명령을 해석하고 실행하는 하위 쉘을 생성합니다. 이 모델에서, 스크립트는 Bourne 셸 내에서 호출되는 경우에만 다른 명령처럼 작동합니다. 운영 시스템 자체의 exec() 시스템 호출을 통해 그러한 파일을 직접 실행하려는 시도는 실패하여, 스크립트가 통상의 시스템 명령처럼 균일하게 작동하지 못하게 합니다.
Version 8 improved shell scripts
이후 버전의 유닉스-계열 시스템에서, 이러한 불일치가 제거되었습니다. Dennis Ritchi는 1980년 1월 버전 8 Unix에 대한 인터프리터 지시문에 대한 커널 지원을 다음 설명과 함께 도입했습니다:
From uucp Thu Jan 10 01:37:58 1980
>From dmr Thu Jan 10 04:25:49 1980 remote from research
The system has been changed so that if a file being executed
begins with the magic characters #! , the rest of the line is understood
to be the name of an interpreter for the executed file.
Previously (and in fact still) the shell did much of this job;
it automatically executed itself on a text file with executable mode
when the text file's name was typed as a command.
Putting the facility into the system gives the following
benefits.
1) It makes shell scripts more like real executable files,
because they can be the subject of 'exec.'
2) If you do a 'ps' while such a command is running, its real
name appears instead of 'sh'.
Likewise, accounting is done on the basis of the real name.
3) Shell scripts can be set-user-ID.[a]
4) It is simpler to have alternate shells available;
e.g. if you like the Berkeley csh there is no question about
which shell is to interpret a file.
5) It will allow other interpreters to fit in more smoothly.
To take advantage of this wonderful opportunity,
put
#! /bin/sh
at the left margin of the first line of your shell scripts.
Blanks after ! are OK. Use a complete pathname (no search is done).
At the moment the whole line is restricted to 16 characters but
this limit will be raised.
Unnamed shell script feature
어쨌든, 이 기능의 제작자는 이름을 지정하지 않았습니다:
From: "Ritchie, Dennis M (Dennis)** CTR **" <dmr@[redacted]>
To: <[redacted]@talisman.org>
Date: Thu, 19 Nov 2009 18:37:37 -0600
Subject: RE: What do -you- call your #!<something> line?
I can't recall that we ever gave it a proper name.
It was pretty late that it went in--I think that I
got the idea from someone at one of the UCB conferences
on Berkeley Unix; I may have been one of the first to
actually install it, but it was an idea that I got
from elsewhere.
As for the name: probably something descriptive like
"hash-bang" though this has a specifically British flavor, but
in any event I don't recall particularly using a pet name
for the construction.
인터프리터 지시문에 대한 커널 지원은 다른 버전의 Unix로 확산되었고, 최신 구현 중 하나는 fs/binfmt_script.c의 리눅스 커널 소스에서 볼 수 있습니다.
이 메커니즘은 스크립트를 정규 컴파일된 프로그램이 될 수 있는 거의 임의의 컨텍스트에서 사용되는 것을 허용하며, 여기에는 전체 시스템 프로그램과 심지어 다른 스크립트의 인터프리터도 포함됩니다. 그러나 경고로, 일부 초기 버전의 커널 지원은 인터프리터 지시문의 길이를 약 32자로 제한했고 (첫 번째 구현에서는 16자에 불과), 지시문의 모든 매개변수에서 인터프리터 이름을 분리하지 못했거나 다른 문제가 있었습니다. 추가적으로, 일부 최신 시스템에서는 보안 목적으로 전체 메커니즘을 제한하거나 비활성화할 수 있습니다 (예를 들어, 많은 시스템에서 스크립트에 대한 set-user-id 지원이 비활성화되었습니다).
#! 매직 넘버에 대한 완전한 커널 지원을 갖는 시스템에서도 인터프리터 지시어가 없는 일부 스크립트 (보통은 여전히 실행 권한이 필요하지만)는 여전히 Bourne 쉘의 레거시 스크립트 처리 덕분에 실행이 가능하며, 이는 많은 현대적 후손에 여전히 존재합니다. 스크립트는 그런 다음 사용자의 기본 쉘에 의해 해석됩니다.