Source

어떤 SHELL을 사용하고 있는지 확인해보자.

어러 쉘이 있다. sh(Bourne Shell)을 기반으로 하는 Bash(Bourne-again shell), zsh(Z shell) 등은 문법이 거의 똑같지만 완전히 같지는 않다. 쉘스크립트를 만들어 실행 하는 경우 #! 지시자로 사용할 쉘을 지정할 수 있기 때문에 크게 문제가 없지만 source 명령이나 dot(.) 명령으로 현재 환경(Current Environment Context)에서 스크립트를 실행하는 경우 사용중인 쉘의 종류에 따라 문법이 달라 문제가 발생 할 수 있다. 주의해서 처리 하도록 하자.

기본쉘을 Zsh 사용하기 시작하면서 겪은 문제다. 보통 리눅스에서 기본쉘은 Bash 이기 때문에 거의 모든 프로그램들이 Bash 위주로 구현되어 있기 때문에 발생 하는 문제이다.

대부분 다음과 같은 문제이다.

실행 스크립트의 파일 이름을 알고 싶을때 Bash에서는 $BASH_SOURCE를 사용한다. 하지만 이 변수는 Bash 에서만 지원됨으로 Zsh에서는 $0 변수를 사용해야 된다. Bash에서도 $0변수를 지원하지만 Bash에서 $0 변수를 사용하면 쉘의 정보((bash)가 표시된다.

쉘스크립트에서 $0 는 실행파일의 이름을 나타내는 변수 이다. Bash에서 $0 변수는 쉘이 시작할 때만 초기화 되지만 dot 명령은 새로운 쉘을 시작하는 것이 아니라 현재 쉘의 컨텍스트에서 실행 하는 것이므로 쉘에서 echo $0 를 실행한것과 같은 결과(즉, bash)가 출력된다. 그런데 Zsh 에서는 $0가 스크립트 이름으로 세팅된다.

구글링을 해보면 Zsh에서 Bash$BASH_SOURCE 와 가장 가까운 결과를 내는것은 ${(%):-%x} 라고 한다. 하지만 $0도 같은 결과는 내기 때문에 그냥 사용하기로 한다.

다음은 ./env 파일의 내용이다.

1
2
echo \$BASH_SOURCE = $BASH_SOURCE
echo \$0 = $0

각 SHELL에서 실행 해 보자

. ./env

다음과 같은 출력을 얻을 수 있다.

bash

$BASH_SOURCE = ./env
$0 = bash

zsh

$BASH_SOURCE =
$0 = ./env

따라서 실행 되는 스크립트의 이름 알기 위해서는 다음과 같이 쉘에 따라 다른 방식을 정용하여야 한다.

SH_NAME=$(basename $(readlink /proc/$$/exe))

case ${SH_NAME} in
	"zsh") SELF=$(realpath $0) ;;
	"bash") SELF=$(realpath ${BASH_SOURCE[0]}) ;;
	*) echo "Unknown SHELL $SH_NAME" && exit 0 ;;
esac

echo $SELF

Bash 또는 Zsh 만 사용한다면 다음과 같이 사용해도 같은 결과를 얻을 수 있다.

SELF=$(realpath ${BASH_SOURCE[0]:-$0})
echo $SELF

아래와 같이 env 파일을 만들고 dot command로 실행해보자

SELF=${BASH_SOURCE[0]:-$_}
echo $(basename $SELF) is located at $(realpath $SELF)

env 파일 실행

. ./env

Bash, Zsh 둘다 같은 결과를 얻을 수 있다.

env is located at /home/euikook/src/env

$SHELL

/etc/password 파일에 정의된 사용자에 할당된 SHELL 출력한다.

echo $SHELL

Cons

지정된 쉘 정보를 표시 하지만 현재 사용중인 SHELL 정보를 출력하지 않는다.

$ cat /etc/passwd | grep $USER
john:x:1000:1000::/home/john:/usr/bin/zsh

cat 명령으로 /etc/passwd 파일을 확인 결과 /usr/bin/zsh 가 쉘로 할당되어 있다.

아래와 같이 bash로 쉘을 변경 후 $SHELL$0 정보를 출력 해보자.

$ bash
$ echo echo User SHELL is $SHELL, Current SHELL is $0
User SHELL is /usr/bin/zsh, Current SHELL is bash