Shebang 없이 스크립트를 실행하는 쉘 인터프리터는 무엇입니까?

Shebang 없이 스크립트를 실행하는 쉘 인터프리터는 무엇입니까?

내 계정의 기본 셸이 zsh이지만 터미널을 열고 bash를 시작하고 라는 스크립트를 실행한다고 가정합니다. prac002.shzsh 또는 bash 중 어떤 셸 인터프리터가 스크립트를 실행하는 데 사용됩니까? 다음 예를 고려하십시오.

papagolf@Sierra ~/My Files/My Programs/Learning/Shell % sudo cat /etc/passwd | grep papagolf
[sudo] password for papagolf: 
papagolf:x:1000:1001:Rex,,,:/home/papagolf:/usr/bin/zsh
# papagolf's default shell is zsh

papagolf@Sierra ~/My Files/My Programs/Learning/Shell % bash
# I fired up bash. (See that '%' prompt in zsh changes to '$' prompt, indicating bash.)

papagolf@Sierra:~/My Files/My Programs/Learning/Shell$ ./prac002.sh 
Enter username : Rex
Rex
# Which interpreter did it just use?

**편집:** 스크립트 내용은 다음과 같습니다.

papagolf@Sierra ~/My Files/My Programs/Learning/Shell % cat ./prac002.sh 
read -p "Enter username : " uname
echo $uname

답변1

어떤 인터프리터를 사용할지 나타내기 위해 스크립트가 #!shebang 줄로 시작하지 않기 때문에,POSIX 라고:

만약에execl()POSIX.1-2008용 시스템 인터페이스 볼륨에 정의된 [ENOEXEC] 오류에 해당하는 오류로 인해 함수가 실패했습니다.쉘은 검색 결과의 경로 이름을 첫 번째 피연산자로 사용하여 쉘을 호출하는 것과 동일한 명령을 실행해야 합니다., 새 셸의 "$0" 값을 명령 이름으로 설정할 수 있다는 점을 제외하고 나머지 인수를 새 셸에 전달합니다. 실행 파일이 텍스트 파일이 아닌 경우 쉘은 이 명령 실행을 우회할 수 있습니다. 이 경우 오류 메시지를 작성하고 종료 상태 126을 반환해야 합니다.

이 표현은 약간 모호하며 쉘마다 해석이 다릅니다.

이 경우,Bash는 자체적으로 스크립트를 실행합니다.. 반면에 zsh에서 실행하면,zsh는 사용할 것이다sh(시스템에 있는 모든 것).

이 경우 스크립트에 다음 줄을 추가하여 동작을 확인할 수 있습니다.

echo $BASH_VERSION
echo $ZSH_VERSION

Bash에서 첫 번째 줄은 버전을 인쇄하지만 두 번째 줄은 어떤 셸을 사용하든 아무 것도 표시하지 않습니다.

  • 예 를 /bin/sh들어 dashzsh 또는 dash에서 스크립트를 실행하면 두 줄 모두 아무것도 출력되지 않습니다.
  • Bash에 연결하는 경우 /bin/sh모든 경우에 첫 번째 출력 줄이 표시됩니다.
  • 만약 /bin/sh그것이라면다른 버전Bash를 직접 사용하는 것과 bash 및 zsh에서 직접 스크립트를 실행하면 다른 출력이 표시됩니다.

이것ps -p $$롤 답변의 명령스크립트를 실행하기 위해 셸에서 사용하는 명령에 대한 유용한 정보도 표시됩니다.

답변2

파일은 시스템에서 인식하는 어떤 종류의 실행 파일도 아니며 사용자에게 파일 실행 권한이 있다고 가정할 때 시스템 execve()호출은 일반적으로 다음과 함께 실패합니다 ENOEXEC.실행파일이 아닙니다) 실수.

다음에 일어날 일은 명령을 실행하는 데 사용되는 응용 프로그램 및/또는 라이브러리 기능에 따라 다릅니다.

execlp()예를 들어 쉘, / libc 함수일 수 있습니다 execvp().

대부분의 다른 응용 프로그램은 명령을 실행할 때 이들 중 하나를 사용합니다. 예를 들어 명령줄을 구문 분석하기 위해 system("command line")일반적으로 호출되는 libc 함수를 통해 셸을 호출 하거나 sh(해당 경로는 컴파일 시간에 결정될 수 있음(예: Solaris의 경우 /bin/sh)) 다음을 사용하는 명령과 같이 자체 /usr/xpg4/bin/sh저장된 셸을 호출합니다. 또는 다른 많은 명령(대신 사용자의 로그인 쉘을 호출함).$SHELLvi!xterm -e 'command line'su user -c$SHELL

일반적으로 시작하지 않는 shebang-less 텍스트 파일은 스크립트 #로 간주됩니다 sh. 그러나 구체적인 상황은 sh다양할 수 있습니다.

execlp()/ execvp(), 일반적으로 execve()반환 시 ENOEXEC호출됩니다 sh. 여러 표준을 사용하는 시스템의 경우 sh여러 표준을 준수할 수 있으므로 이는 sh일반적으로 컴파일 타임에 결정됩니다(응용 프로그램은 다른 경로를 참조하는 다른 코드 블록을 연결하여 사용 execvp()/ 링크합니다 ). 예를 들어, Solaris에서는 (표준, POSIX ) 또는 (Solaris 10 및 이전 버전에서는 Bourne 쉘(구식 쉘), Solaris 11에서는 ksh93) 이 됩니다 .execlp()sh/usr/xpg4/bin/shsh/bin/sh

조개껍질에는 다양한 변형이 있습니다. bash, AT&T, Bourne 쉘은 일반적으로 (하위 프로세스를 사용하지 않는 한) 시뮬레이션 후 스크립트 자체를 해석합니다. ksh즉, 내보내지 않은 모든 변수를 설정 해제하고, 실행 시 닫기 fd를 모두 닫고, 모든 사용자 정의 트랩, 별칭, 함수를 제거합니다... .(스크립트 모드에서 해석됩니다). 그것을 해석하기 위해 자체적으로 실행됩니다(모드에서 그렇게 사용).execexecve()bashshyashshargv[0]sh

zshpdksh, 을 기반으로 하는 쉘이 ash일반적으로 호출됩니다 sh(해당 경로는 컴파일 타임에 결정됩니다).

cshand tcsh(및 일부 초기 BSD) 의 sh경우 파일의 첫 번째 문자가 #이면 해석하기 위해 스스로 실행되고 sh그렇지 않으면 실행됩니다. 이것은 csh실제로 #주석으로 인식되었지만 Bourne 쉘에서는 인식되지 않았던 Shebang 이전 시대로 거슬러 올라갑니다. 따라서 #csh 스크립트임을 암시합니다.

fish(최소 버전 2.4.0) execve()실패하면 오류만 반환합니다(스크립트로 처리하려고 시도하지 않음).

일부 쉘(예: bashAT&T ksh)은 먼저 파일이 스크립트일 수 있는지 경험적으로 판단하려고 시도합니다. 따라서 스크립트의 처음 몇 바이트에 NUL 문자가 있는 경우 일부 쉘은 스크립트 실행을 거부할 수 있습니다.

또한 execve()ENOEXEC가 실패했지만 파일에 shebang 줄이 있으면 일부 쉘은 shebang 줄 자체를 해석하려고 시도합니다.

몇 가지 예를 들면 다음과 같습니다.

  • 이면 in 모드로 $SHELL해석 /bin/bash됩니다 . 그리고 using이 사용되므로 스크립트가 해석됩니다.xterm -e 'myscript with args'myscriptbashshxterm -e myscript with argsxtermexecvp()sh
  • su -c myscriptroot로그인 쉘이 Bourne /bin/sh쉘인 Solaris 10에서는 Bourne 쉘이 해석 /bin/sh됩니다 myscript.
  • /usr/xpg4/bin/awk 'BEGIN{system("myscript")'/usr/xpg4/bin/shSolaris 10에서는 (와 동일 ) 로 해석됩니다 /usr/xpg4/bin/env myscript.
  • find . -prune -exec myscript {} \;Solaris 10(사용)에서는 POSIX 환경에서도 Even execvp()로 해석됩니다 (일관성 오류)./bin/sh/usr/xpg4/bin/find
  • csh -c myscriptcsh로 시작하면 그렇지 않은 #것으로 해석됩니다 sh.

요약하자면, 스크립트가 어떻게, 무엇에서 호출되는지 모르면 스크립트를 해석하는 데 어떤 셸을 사용할지 결정할 수 없습니다.

어쨌든 read -p이는 단지 bash구문일 뿐이므로 스크립트가 해석되었는지 확인해야 합니다 bash(그리고 오해의 소지가 있는 .sh확장을 피해야 함). 실행 파일의 경로를 알고 bash다음을 사용합니다.

#! /path/to/bash -
read -p ...

또는 다음 명령을 사용하여 실행 파일을 $PATH찾을 수 있습니다 bash(설치되어 있다고 가정).bash

#! /usr/bin/env bash
read -p ...

( env거의 모든 곳에서 /usr/bin). 또는 POSIX+Bourne과 호환되게 만들 수 있으며, 이 경우 /bin/sh./bin/sh

#! /bin/sh -
printf >&2 'Enter a user name: '
read user
printf '%s\n' "$user"

답변3

어떤 셸이 사용되는지 확인하려면 다음 스크립트를 실행할 수 있습니다.

ps -p $$
echo -n "The real shell is: "
realpath /proc/$$/exe

내 컴퓨터에서 나는

  PID TTY          TIME CMD
13718 pts/16   00:00:00 sh
The real shell is: /usr/bin/bash

내 기본 쉘이다루기 힘든. 그것은 사용한다세게 때리다내 컴퓨터에서는명령은 다음을 통해 구현됩니다.세게 때리다그리고다루기 힘든추천shebang이 지정되지 않은 경우.

관련 정보