1. 사용 명령어 |
(1) exec
2. 키워드 & 사용처 |
(1) 키워드
래퍼, 환경 변수
(2) 사용처
래퍼 스크립트를 작성하고 싶을 때 사용합니다.
3. 실행 예제 |
$ ./exec.sh -o output.txt <- myappd가 실행됨
4. 스크립트 |
#!/bin/sh
# TMPDIR 환경 변수 설정
TMPDIR=/"disk1/tmp"
export TMPDIR
# exec 명령어로 myappd 실행. 명령행 인수를 "$@"로 넘김
exec ./myappd "$@" ①
5. 해설 |
이 스크립트는 환경 변수 TMPDIR을 "/disk1/tmp"로 설정하고 현재 디렉터리에 있는 myappd 프로그램을 실행합니다. 여기서 myappd는 환경 변수 TMPDIR을 임시 디렉터리로 사용하는 프로그램이라고 가정합니다.
예제처럼 환경 변수 등을 자체적으로 설정하고 다른 프로그램을 실행하는 프로그램을 래퍼라고 부릅니다. 이런 래퍼 스크립트는 특히 데몬 같은 상주형 애플리케이션을 실행할 때 자주 사용합니다. 예를 들어 자바 서블릿 컨테이너로 유명한 톰캣(Tomcat)은 기동하는 스크립트 startup.sh로 다음처럼 작성해서 catalina.sh를 래퍼합니다.
... 생략 ...
PRGDIR=`dirname "$PRG" `
EXECUTABLE=catalina.sh
... 생략 ...
exec "$PRGDIR"/"$EXECUTABLE" start "$@"
그럼 래퍼 스크립트로 프로그램을 실행할 때 ①처럼 exec 명령어를 사용하는 것이 일반적입니다. 단순히 외부 프로그램을 실행한다면 다음처럼 작성하면 됩니다. 하지만 이런 상주형 서버 프로그램을 기동할 때는 그다지 사용하지 않는 방법입니다.
./myappd "$@"
왜 exec 명령어를 사용하는 것이 좋은지 이해하려면 셸이 외부프로그램을 실행할 때 OS 동작을 알아야 합니다. 그럼 간단히 셸과 명령어 실행 흐름을 알아봅니다.
셸이 명령어를 실행할 때 외부에서는 다음처럼 동작합니다. 여기에 나오는fork, exec, exit는 시스템 콜로 명령어가 아닙니다.
이때 OS에 있어 가장 부하가 높은 것은 fork로 프로세스를 생성하는 일입니다. 따라서 프로그래머는 꼭 필요할 때만 프로세스를 생성해야 합니다.
①에서 이용하는 exec 명령어를 쓰면 셸은 fork하지 않고 현재 셸로 직접 exec 시스템 콜을 발행합니다. 따라서 여분의 프로세스를 생성하지 않아도 됩니다. 만약 여기서 exec를 사용하지 않고 직접 실행하면 셸은 myappd가 끝날 때까지 기다립니다. myappd가 상주형 서버 프로그램이면 부모 프로세스 셸은 잉여 프로세스가 됩니다. exec 명령어를 사용해서 이런 프로세스가 발생하는 걸 방지할 수 있습니다.
셸 하나 정도라면 별일 없겠지만 예를 들어 myappd가 서버 상주형 프로그램으로 동시에 여러 개 실행된다고 하면 수 많은 셸 프로세스가 쓸데없이 존재하게 됩니다. 따라서 예제처럼 래퍼 스크립트를 작성할 때는 리소스를 아끼기 위해 exec 명령어를 써서 외부 프로그램을 실행하는 것이 좋습니다.
①은 "$@"을 써서 셸 스크립트에 지정한 명령행 인수를 실제 명령어에 그대로 넘깁니다. $@은 명령행 인수 전체를 나타내는 특수 변수로 "$@" 처럼 위치 인수를 순서대로 따옴표로 싸서 지정한 것과 같습니다.
기호 | 의미 |
$@ | $1, $2, $3, ... |
"$@" | "$1" "$2" "$3" ... |
이렇게 해서 "$@"을 실행할 명령어 인수로 넘겨서 원래 인수를그대로 외부 명령어에 지정할 수 있습니다.
<주의사항>
명령행 인수 전부를 의미하는 표현으로 $*가 있습니다. 하지만 이 변수는 이런 래퍼에서는 사용할 수 없습니다.
기호 | 의미 |
$* | $1 $2 $3 ... |
"$*" | "$1 $2 $3" ... |
큰따옴표로 둘러쌀 때 위치 인수마다 " "로 처리하는 것이 아니라 인수 전체를 하나의 문자열로 다룹니다. 따라서 인수를 다룰 때 $*를 사용하는 경우는 많지 않습니다."$*"이 아니라 "$@"를 사용한다고 기억해두기 바랍니다.
참고서적 : 유닉스 리눅스 셸 스크립트 예제 사전
댓글