shebang은 스크립트를 실행하는 쉘을 결정합니까?


84

이것은 어리석은 질문 일지 모르지만 여전히 묻습니다. 내가 세방을 선언하면

#!/bin/bash 

의 시작 부분에서 my_shell_script.sh항상 bash를 사용 하여이 스크립트를 호출해야합니까

[my@comp]$bash my_shell_script.sh

또는 예를 들어 사용할 수 있습니까

[my@comp]$sh my_shell_script.sh

내 스크립트는 shebang을 사용하여 실행중인 쉘을 결정합니까? ksh쉘 에서도 마찬가지 입니까? AIX를 사용하고 있습니다.


6
"_some_shell some_script"를 수행하면 _some_shell이 ​​시작되고 some_script를 해석하도록 요청합니다. 따라서 "sh my_shell_script.sh"를 수행하면 shebang을 해석하지 않지만 대신 sh로 스크립트를 해석합니다. 다음 오두막 사용 chmod +x my_shell_script.sh ; /path/to/my_shell_script.sh # or ./my_shell_script.sh if you happen to be in its directory
올리비에 Dulac

답변:


117

오두막은 #! 의 사람이 읽을 수있는 인스턴스 매직 넘버 바이트 문자열로 구성 0x23 0x21의해 사용, exec()실행해야 할 파일이 스크립트 나 바이너리 여부를 확인하는 기능의 가족. shebang이 있으면 exec()대신 shebang 다음에 지정된 실행 파일을 실행합니다.

이것은 질문에 주어진 경우 모두 에서 수행 된 것처럼 명령 줄에 인터프리터를 지정하여 스크립트를 호출하면 명령 줄에 exec()지정된 인터프리터를 실행하고 스크립트를 보지도 않음을 의미합니다.

따라서 다른 사람들이 지적했듯이 exec()shebang 행에 지정된 인터프리터를 호출하려면 스크립트에 실행 가능 비트가 설정되고로 호출되어야합니다 ./my_shell_script.sh.

다음 스크립트를 사용하면 동작을 쉽게 보여줄 수 있습니다.

#!/bin/ksh
readlink /proc/$$/exe

설명:

  • #!/bin/kshksh통역사로 정의 합니다.

  • $$ 현재 프로세스의 PID를 보유합니다.

  • /proc/pid/exe 프로세스 실행 파일에 대한 심볼릭 링크입니다 (적어도 Linux에서는; AIX에서 /proc/$$/object/a.out은 실행 파일에 대한 링크 임).

  • readlink 심볼릭 링크의 값을 출력합니다.

예:

참고 : 나는 기본 쉘은 우분투에이 보여주는거야 /bin/sh하는 심볼릭 링크 대시/bin/dash/bin/ksh에 심볼릭 링크 /etc/alternatives/ksh차례에 심볼릭 링크이다 /bin/pdksh.

$ chmod +x getshell.sh
$ ./getshell.sh 
/bin/pdksh
$ bash getshell.sh 
/bin/bash
$ sh getshell.sh 
/bin/dash

이 답변에 대해 Thomas에게 감사드립니다. Node.js 또는 Java 등에서 하위 프로세스로 스크립트를 실행하는 것처럼 가장하십시오. "exec"프로세스를 시작하면 exec가 쉘 스크립트를 실행할 수 있습니까? 나는이 질문에 대한 답을 찾고 있기 때문에 묻습니다 : stackoverflow.com/questions/41067872/…
Alexander Mills

1
@AlexanderMills exec()이 답변에서 언급 된 것은 시스템 호출이며, 명령 exec은 쉘 내장이므로 Node.js 또는 Java에서 exec 프로그램 을 호출 할 수 없습니다 . 그러나 Runtime.exec()Java 등에서 호출 한 모든 쉘 명령 은 결국 exec()시스템 호출에 의해 처리됩니다 .
Thomas Nyman

허, 예, 방금 언급 한 Java API에 익숙합니다. Node.js에서 낮은 수준의 exec () 호출을 호출 할 수있는 방법이 있는지 궁금합니다.
Alexander Mills

@AlexanderMills 나는 child_process.{exec(),execFile(),spawn()C를 exec()통해 구현 될 것이라고 상상할 것이다 process.
Thomas Nyman

10

그렇습니다. 그건 그렇고 그것은 바보 같은 질문이 아닙니다. 내 답변에 대한 참조는 여기에 있습니다 . #으로 스크립트 시작하기!

  • 그것은 shebang 또는 "bang"라인이라고합니다.

  • Bash 인터프리터의 절대 경로 일뿐입니다.

  • 숫자 기호와 느낌표 문자 (#!)로 구성되며 / bin / bash와 같은 인터프리터의 전체 경로가 이어집니다.

    Linux의 모든 스크립트는 첫 번째 줄에 지정된 인터프리터를 사용하여 실행됩니다. 거의 모든 bash 스크립트는 종종 #! / bin / bash로 시작합니다 (Bash가 / bin에 설치되었다고 가정). 다른 쉘에서 실행되는 경우. Shebang은 Bell Laboratories의 Dennis Ritchie가 버전 7 Unix와 8 사이에서 소개했습니다. 그런 다음 버클리의 BSD 라인에도 추가되었습니다.

통역 라인 무시하기 (셰방)

인터프리터 라인을 지정하지 않으면 기본값은 일반적으로 / bin / sh입니다. 그러나 #! / bin / bash 줄을 설정하는 것이 좋습니다.


3
자세히 설명하기 위해 커널은 정적으로 링크 된 바이너리를 실행하는 방법과 다른 사람들을위한 인터프리터 정보를 찾을 수있는 위치 (바이너리 또는 shebang 행의 특수 필드) 만 알고 있습니다. 일반적으로 쉘 스크립트를 실행한다는 것은 shebang 행을 쉘로 따르고 쉘 바이너리의 DT_INTERP 필드를 따라 동적 링커를 따르는 것을 의미합니다.
Simon Richter

5
또한 이것은 셸 스크립트에만 국한되지 않습니다. 모든 텍스트 기반 스크립트 파일이이를 사용합니다. 예 : #!/usr/bin/perl #!/usr/local/bin/python #!/usr/local/bin/ruby여러 시스템을 지원하는 데 사용되는 또 다른 일반적인 shebang 항목은 env를 사용하여 사용하려는 인터프리터를 찾는 것입니다.#!/usr/bin/env perl #!/usr/bin/env python
sambler

@sambler 말하기 env, 실제로 선호 해야하는 것은 무엇입니까? 파이썬과 Perl은 종종을 사용 env하지만 쉘 스크립트에서는 종종 생략되며 shebang은 해당 쉘을 가리 킵니다.
polemon

1
@polemon이 적고 경로가 다양합니다. 기본 쉘은 모든 시스템에서 동일한 경로에 있습니다. 최신 버전의 perl 및 python을 다른 시스템의 다른 위치에 설치할 수 있으므로 env를 사용하면 동일한 shebang이 항상 작동하므로 env가 쉘 스크립트보다 perl 및 python 스크립트에 더 많이 사용됩니다.
sambler

env$ PATH에서 프로그램을 찾는 것은 약간의 해킹입니다. 이름에서 알 수 있듯이 환경 변수를 설정하지 않습니다. $ PATH는 사용자마다 결과가 다를 수 있습니다. 그러나 합리적인 perl 인터프리터를 이상한 장소에 배치하는 시스템에서 스크립트를 수정하지 않고 실행할 수 있습니다.
John Mahowald

4

execLinux 커널 의 시스템 호출은 #!기본적으로 shebang을 이해합니다 ( )

bash에서 할 때 :

./something

Linux에서는 exec경로를 사용 하여 시스템 호출을 호출합니다 ./something.

이 커널 라인은 https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_script.c#L25에 전달 된 파일에서 호출됩니다 exec.

if ((bprm->buf[0] != '#') || (bprm->buf[1] != '!'))

파일의 첫 바이트를 읽고와 비교합니다 #!.

비교가 참이면 나머지 행은 Linux 커널에 의해 구문 분석되어 exec경로 /usr/bin/env python와 현재 파일을 첫 번째 인수로 사용하여 다시 호출 합니다.

/usr/bin/env python /path/to/script.py

이것은 #주석 문자로 사용 되는 모든 스크립팅 언어에서 작동 합니다.

그리고 네, 당신은 무한 루프를 만들 수 있습니다 :

printf '#!/a\n' | sudo tee /a
sudo chmod +x /a
/a

배시는 오류를 인식합니다.

-bash: /a: /a: bad interpreter: Too many levels of symbolic links

#! 사람이 읽을 수 있지만 반드시 필요한 것은 아닙니다.

파일이 다른 바이트로 시작된 경우 exec시스템 호출은 다른 핸들러를 사용합니다. 다른 가장 중요한 기본 핸들러는 ELF 실행 파일입니다 : https://github.com/torvalds/linux/blob/v4.8/fs/binfmt_elf.c#L1305 바이트를 확인하는 7f 45 4c 46인간으로 발생하는 ( 에 읽을 수 있음 .ELF). /bin/lsELF 실행 파일 인의 첫 번째 4 바이트를 읽음으로써 확인하십시오 .

head -c 4 "$(which ls)" | hd 

산출:

00000000  7f 45 4c 46                                       |.ELF|
00000004                                                                 

따라서 커널이 해당 바이트를 볼 때 ELF 파일을 가져 와서 메모리에 올바르게 넣고 새 프로세스를 시작합니다. 참조 : https : //.com/questions/8352535/how-does-kernel-get-an- executable-binary-file-running-under-linux / 31394861 # 31394861

마지막으로, binfmt_misc메커니즘을 사용하여 자체 Shebang 처리기를 추가 할 수 있습니다 . 예를 들어, 파일에 대한 사용자 정의 핸들러를.jar 추가 할 수 있습니다 . 이 메커니즘은 파일 확장자 별 핸들러도 지원합니다. 다른 응용 프로그램은 QEMU를 사용하여 다른 아키텍처의 실행 파일투명하게 실행하는 것 입니다.

POSIX가 shebang을 지정하지는 않는다고 생각합니다 : https://unix.stackexchange.com/a/346214/32558 비록 이론적 근거 섹션에서 언급하고 있지만 "실행 가능한 스크립트가 시스템에서 지원되는 경우 발생할 수 있습니다 ".


1
./something쉘에서 실행 하면 전체 경로는로 전달되지 exec않지만 정확히 입력 된 경로는 전달됩니다. 당신의 대답에서 이것을 고칠 수 있습니까? 수행 echo "$0"스크립트에서 당신은이 경우에 표시됩니다.
AndiDog

2

사실, 결과적으로 Shebang 행에 표시된 실행 파일은 실행 파일 일뿐입니다. 일부 텍스트 인터프리터를 실행 파일로 사용하는 것이 좋지만 반드시 그럴 필요는 없습니다. 설명과 시연을 위해 다소 쓸모없는 테스트를했습니다.

#!/bin/cat
useless text
more useless text
still more useless text

파일 이름을 test.txt로 지정하고 실행 가능 비트를 설정 chmod u+x test.txt한 다음 "호출"합니다 ./test.txt. 예상대로 파일의 내용이 출력됩니다. 이 경우 고양이는 shebang 라인을 무시하지 않습니다. 단순히 모든 라인을 출력합니다. 따라서 모든 유용한 통역사는이 shebang 라인을 무시할 수 있어야합니다. bash, perl 및 PHP의 경우 단순히 주석 줄입니다. 예, 이것들은 shebang 라인을 무시합니다.


-1

내가 수집 한 것부터 파일에 실행 가능 비트 세트가 있고 호출 될 때마다 커널은 파일 헤더를 분석하여 진행 방법을 결정합니다 (알고있는 한 LKM을 통해 사용자 정의 파일 형식에 대한 사용자 정의 처리기를 추가 할 수 있음). 파일이 #! 인 텍스트 파일 인 경우 처음에 조합하면, 실행은 다른 실행 파일 (보통 일종의 쉘)로 전달되며, 경로는 해당 shebang 바로 다음에 같은 경로로 지정됩니다. 그런 다음 커널은 셸을 실행하고 처리 할 파일을 전달합니다.

간단히 말해서 어떤 쉘을 사용하여 스크립트를 호출하든 상관 없습니다. 커널은 어느 쪽이든 적절한 방법으로 실행을 디스패치합니다.


4
bash ./myscript.sh와 사이에 뚜렷한 차이가 ./myscript.sh있습니다.
CVn

이 "표시된 차이"는 무엇을 의미합니까?
jrara

3
@ jrara 내 대답을 참조하십시오. "스크립트를 호출하는 쉘은 중요하지 않습니다."라는 말은 사실이 아닙니다.
Thomas Nyman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.