어떤 쉘 인터프리터가 shebang없이 스크립트를 실행합니까?


17

내 계정의 기본 쉘이 zsh라고 가정하지만 터미널을 열고 bash를 시작하고라는 스크립트를 실행했습니다 prac002.sh.이 쉘 해석기는 스크립트 zsh 또는 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

스크립트는 상단에 무엇을 말합니까?
Michael Homer

@MichaelHomer : 아무것도 아닙니다. 스크립트의 내용을 추가하기 위해 질문을 편집했습니다. 스크립트에 실행 권한이 있습니다.
7_R3X

현재 쉘을 사용하려면 . prac002.sh스크립트가 현재 디렉토리에 있다고 가정 하고에서 와 같이 점을 소싱하십시오 .
thecarpy 2016 년

1
실행 . ./prac002.sh하면 현재 쉘, 즉 도트 ( .), 공백 (), 스크립트 경로가 함께 실행됩니다. 이것을 스크립트의 도트 소싱이라고합니다. ;-)
thecarpy 2016 년

답변:


19

스크립트가 #!사용할 인터프리터를 나타내는 shebang 줄로 시작하지 않기 때문에 POSIX는 다음과 같이 말합니다 .

는 IF execl()함수 POSIX.1-2008의 시스템 인터페이스 볼륨에 정의 [ENOEXEC] 에러 에러 당량 인해 실패 쉘는 최초로 검색 인한 경로 호출 쉘 데에 유사한 명령을 실행한다 새 쉘에서 "$ 0"값이 명령 이름으로 설정 될 수 있다는 점을 제외하고 나머지 인수가 새 쉘로 전달 된 operand 실행 파일이 텍스트 파일이 아닌 경우, 쉘은이 명령 실행을 생략 할 수 있습니다. 이 경우 오류 메시지를 작성하고 종료 상태 126을 리턴해야합니다.

그 문구는 약간 모호하며, 다른 껍질은 다른 해석을 가지고 있습니다.

이 경우 Bash는 자체를 사용하여 스크립트를 실행합니다 . 반면에 zsh에서 대신 실행 한 경우 zsh는sh (시스템에있는 모든 것을) 대신 사용합니다.

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

echo $BASH_VERSION
echo $ZSH_VERSION

Bash에서 첫 번째 줄은 버전을 출력하지만 두 번째 줄은 사용하는 쉘에 관계없이 아무 것도 말하지 않습니다.

  • /bin/sh가 is 인 경우 dash스크립트가 zsh 또는 dash에서 실행될 때 어느 행도 아무것도 출력하지 않습니다.
  • 당신이 경우 /bin/sh배쉬에 대한 링크, 당신은 모든 경우에 첫 번째 줄의 출력을 확인할 수 있습니다.
  • 경우 /bin/shA는 다른 버전의 직접 사용하는 것보다 배쉬의 당신이 직접 zsh을에서 떠들썩한 파티에서 스크립트를 실행할 때, 당신은 다른 출력을 볼 수 있습니다.

ps -p $$rools의 대답에서 명령은 또한 쉘 스크립트를 실행하는 데 사용되는 명령에 대한 유용한 정보를 표시합니다.


그러나 지정한 기본 쉘에 관계없이 shebang을 지정하지 않으면 DEFAULT SHELL을 사용합니다. 그렇기 때문에 항상 세방을 지정해야합니다.
thecarpy

4
그것은 실제로 답변의 전체 요점이 아닙니다. 두 번째 문장은 확실합니다.
Michael Homer

당신이 맞습니다, bash는 자체를 사용하여 실행합니다. 내 상자의 대부분의 기본 쉘은 .... bash입니다. 난 그냥 새로운 오늘 배운 ... 기본 쉘, 과연, bash는 같은 bash는 실행을 같은 KSH와 Solaris 8에서 감사 뭔가를 테스트 ;-) (upvoted!)
thecarpy

감사. execl()쉘 스크립트에 shebang이없고 다음과 같이 실행될 때 호출 실패가 발생 scriptname합니까? 쉘 스크립트가 다음과 같이 실행될 때 발생하지 bash scriptname않습니까? 쉘 스크립트가 shebang을 포함하고 다음과 같이 실행될 때 발생하지 scriptname않습니까?
StackExchange for April


7

파일이 시스템에서 인식하는 실행 파일 유형이 아니기 때문에 해당 파일을 실행할 수있는 권한이 있다고 가정하면 execve()시스템 호출은 일반적으로 ENOEXEC( 실행 파일 아님) 오류 와 함께 실패 합니다.

그러면 명령을 실행하는 데 사용되는 응용 프로그램 및 / 또는 라이브러리 기능이 결정됩니다.

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

대부분의 다른 응용 프로그램은 명령을 실행할 때 이들 중 하나를 사용합니다. 그들은의 방법으로 예를 들어 쉘을 호출합니다 system("command line")일반적으로 호출합니다 libc의 기능 sh이 명령 줄을 구문 분석 (경로가있는 같은 컴파일 시간 (에서 확인할 수 있습니다 /bin/sh/usr/xpg4/bin/shSolaris에서)) 또는 쉘 된 invoke에 저장 $SHELL처럼 스스로 vi그와 !명령, 또는 xterm -e 'command line'많은 다른 명령 ( su user -c사용자의 로그인 쉘 대신를 호출합니다 $SHELL).

일반적으로 시작하지 않는 shebang-less 텍스트 파일 #sh스크립트 로 간주됩니다 . 어떤 sh이 비록 다를 수 있습니다.

execlp()/ execvp(), execve()돌아올 때 ENOEXEC일반적으로 호출 sh합니다. 개보다이 시스템의 경우 sh그들은 더 이상 표준을 준수 할 수 있기 때문에 sh이 (사용하여 응용 프로그램의 일반적으로 컴파일 시간에 결정 될 것이다 execvp()/ execlp()에 다른 경로를 참조 코드의 다른 덩어리를 연결하여 sh). 예를 들어, Solaris에서는 /usr/xpg4/bin/sh(표준 POSIX sh) 또는 /bin/sh(Solaris 10 이상에서는 Bourne 쉘 (구식 화 된 쉘), Solaris 11에서는 ksh93)이됩니다.

껍질에 관해서는 많은 변형이 있습니다. bash, AT & T ksh, Bourne 쉘은 일반적으로 exec를 시뮬레이션 한 후 스크립트 자체를 해석합니다 ( 사용 되지 않는 한 자식 프로세스에서 ) execve(). 별명, 함수 ... ( bash스크립트를 sh모드 에서 해석 합니다). 해석하기 위해 (모드 에서 yashsh같이) 스스로 실행됩니다 .argv[0]sh

zsh, pdksh, ash기반 셸은 일반적으로 호출한다 sh(컴파일 시간에있는 결정 경로).

에 대한 cshtcsh(과 sh일부 초기 BSD의의), 파일의 첫 번째 문자 인 경우 #, 그들은 스스로 그것을 해석하고 실행합니다 sh그렇지. 그것은 주석으로 csh인식 #되었지만 Bourne 쉘 은 인식하지 못했던 pre-shebang 시간으로 돌아가서 #csh 스크립트라는 힌트였습니다.

fish(최소 버전 2.4.0), execve()실패하면 오류를 반환 합니다 (스크립트로 처리하지 않습니다).

일부 쉘 ( bash또는 AT & T ksh)은 먼저 파일이 스크립트인지 여부를 경험적으로 결정하려고 시도합니다. 따라서 일부 쉘은 처음 몇 바이트에 NUL 문자가 있으면 스크립트 실행을 거부 할 수 있습니다.

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

몇 가지 예가 있습니다.

  • $SHELL이다 /bin/bash, xterm -e 'myscript with args'할 것이다 myscript해석 bashsh모드. 에 있지만 xterm -e myscript with args, xterm사용execvp() 스크립트를 해석 할 수 있도록 sh.
  • su -c myscriptroot로그인 쉘이 있는 Solaris 10 /bin/sh/bin/sh Bourne 쉘인 Bourne 쉘이 myscript해석 했을 것 입니다.
  • /usr/xpg4/bin/awk 'BEGIN{system("myscript")' 솔라리스 10에서 /usr/xpg4/bin/sh (와 동일 /usr/xpg4/bin/env myscript)으로 .
  • find . -prune -exec myscript {} \;Solaris 10 (을 사용하여 execvp())은 다음과 같이 해석합니다./bin/sh 심지어와 /usr/xpg4/bin/find도 POSIX 환경 (적합성 버그)에서.
  • csh -c myscriptcsh시작하면 해석됩니다.# 와, sh그렇지.

어떤 스크립트를 어떻게, 어떻게 호출할지 모르는 경우 스크립트를 해석하는 데 어떤 쉘이 사용 될지 확신 할 수 없습니다.

어쨌든 read -pis- bashonly 구문이므로 스크립트를 해석 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. 대부분의 경우 POSIX와 호환되지만 (대부분의 경우) 대신 Bourne 쉘을 찾을 수 있습니다.

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

1

shebang#! 이라는 줄 이 없으면 sh 가 사용됩니다. 이를 확인하기 위해 다음 스크립트를 실행할 수 있습니다.

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

내 컴퓨터에서

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

기본 쉘이 zsh 인 경우에도 마찬가지 입니다. 내 컴퓨터에서 bash를 사용하므로 sh 명령은 bash에 의해 구현됩니다 .


1
왜 당신은 그것을 공감 했습니까? 설명 하시거나 쓸모가 없습니다 ...
rools

증오 자 (자동 익명 다운 보터)는 증오합니다. 나는 당신의 대답에서 무언가를 배웠으므로 여기에 공감대가 있습니다. :-)
Mac
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.