답변:
오두막은 #!
의 사람이 읽을 수있는 인스턴스 매직 넘버 바이트 문자열로 구성 0x23 0x21
의해 사용, exec()
실행해야 할 파일이 스크립트 나 바이너리 여부를 확인하는 기능의 가족. shebang이 있으면 exec()
대신 shebang 다음에 지정된 실행 파일을 실행합니다.
이것은 질문에 주어진 두 경우 모두 에서 수행 된 것처럼 명령 줄에 인터프리터를 지정하여 스크립트를 호출하면 명령 줄에 exec()
지정된 인터프리터를 실행하고 스크립트를 보지도 않음을 의미합니다.
따라서 다른 사람들이 지적했듯이 exec()
shebang 행에 지정된 인터프리터를 호출하려면 스크립트에 실행 가능 비트가 설정되고로 호출되어야합니다 ./my_shell_script.sh
.
다음 스크립트를 사용하면 동작을 쉽게 보여줄 수 있습니다.
#!/bin/ksh
readlink /proc/$$/exe
설명:
#!/bin/ksh
ksh
통역사로 정의 합니다.
$$
현재 프로세스의 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
exec()
이 답변에서 언급 된 것은 시스템 호출이며, 명령 exec
은 쉘 내장이므로 Node.js 또는 Java에서 exec
프로그램 을 호출 할 수 없습니다 . 그러나 Runtime.exec()
Java 등에서 호출 한 모든 쉘 명령 은 결국 exec()
시스템 호출에 의해 처리됩니다 .
그렇습니다. 그건 그렇고 그것은 바보 같은 질문이 아닙니다. 내 답변에 대한 참조는 여기에 있습니다 . #으로 스크립트 시작하기!
그것은 shebang 또는 "bang"라인이라고합니다.
Bash 인터프리터의 절대 경로 일뿐입니다.
숫자 기호와 느낌표 문자 (#!)로 구성되며 / bin / bash와 같은 인터프리터의 전체 경로가 이어집니다.
Linux의 모든 스크립트는 첫 번째 줄에 지정된 인터프리터를 사용하여 실행됩니다. 거의 모든 bash 스크립트는 종종 #! / bin / bash로 시작합니다 (Bash가 / bin에 설치되었다고 가정). 다른 쉘에서 실행되는 경우. Shebang은 Bell Laboratories의 Dennis Ritchie가 버전 7 Unix와 8 사이에서 소개했습니다. 그런 다음 버클리의 BSD 라인에도 추가되었습니다.
통역 라인 무시하기 (셰방)
인터프리터 라인을 지정하지 않으면 기본값은 일반적으로 / bin / sh입니다. 그러나 #! / bin / bash 줄을 설정하는 것이 좋습니다.
#!/usr/bin/perl
#!/usr/local/bin/python
#!/usr/local/bin/ruby
여러 시스템을 지원하는 데 사용되는 또 다른 일반적인 shebang 항목은 env를 사용하여 사용하려는 인터프리터를 찾는 것입니다.#!/usr/bin/env perl
#!/usr/bin/env python
env
, 실제로 선호 해야하는 것은 무엇입니까? 파이썬과 Perl은 종종을 사용 env
하지만 쉘 스크립트에서는 종종 생략되며 shebang은 해당 쉘을 가리 킵니다.
env
$ PATH에서 프로그램을 찾는 것은 약간의 해킹입니다. 이름에서 알 수 있듯이 환경 변수를 설정하지 않습니다. $ PATH는 사용자마다 결과가 다를 수 있습니다. 그러나 합리적인 perl 인터프리터를 이상한 장소에 배치하는 시스템에서 스크립트를 수정하지 않고 실행할 수 있습니다.
exec
Linux 커널 의 시스템 호출은 #!
기본적으로 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/ls
ELF 실행 파일 인의 첫 번째 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 비록 이론적 근거 섹션에서 언급하고 있지만 "실행 가능한 스크립트가 시스템에서 지원되는 경우 발생할 수 있습니다 ".
./something
쉘에서 실행 하면 전체 경로는로 전달되지 exec
않지만 정확히 입력 된 경로는 전달됩니다. 당신의 대답에서 이것을 고칠 수 있습니까? 수행 echo "$0"
스크립트에서 당신은이 경우에 표시됩니다.
사실, 결과적으로 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 라인을 무시합니다.
내가 수집 한 것부터 파일에 실행 가능 비트 세트가 있고 호출 될 때마다 커널은 파일 헤더를 분석하여 진행 방법을 결정합니다 (알고있는 한 LKM을 통해 사용자 정의 파일 형식에 대한 사용자 정의 처리기를 추가 할 수 있음). 파일이 #! 인 텍스트 파일 인 경우 처음에 조합하면, 실행은 다른 실행 파일 (보통 일종의 쉘)로 전달되며, 경로는 해당 shebang 바로 다음에 같은 경로로 지정됩니다. 그런 다음 커널은 셸을 실행하고 처리 할 파일을 전달합니다.
간단히 말해서 어떤 쉘을 사용하여 스크립트를 호출하든 상관 없습니다. 커널은 어느 쪽이든 적절한 방법으로 실행을 디스패치합니다.
bash ./myscript.sh
와 사이에 뚜렷한 차이가 ./myscript.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