11.1. 작업 제어 명령어

다음에 나올 몇몇 작업 제어 명령어들은 "작업 구분자"(job identifier)를 인자로 받습니다. 이 장 맨 끝에 있는 테이블을 참고하세요.

jobs

백그라운드로 돌고 있는 작업들을 작업 번호와 함께 보여줍니다만, ps만큼 쓸 만하진 않습니다.

참고: 작업(job)과 프로세스에 대해서 혼동하기가 쉬운데, kill, disown, wait같은 내장 명령은 작업 번호나 프로세스 번호, 둘 다, 인자로 받아 들입니다. 하지만 fg, bg, jobs는 오직 작업 번호만 받아 들입니다.

bash$ sleep 100 &
[1] 1384

bash $ jobs
[1]+  Running                 sleep 100 &

"1" 은 작업 번호(현재 쉘에 의해 관리되는 작업들)이고, "1384"는 프로세스 번호(시스템에 의해 관리되는 프로세스들)입니다. 이 작업이나 프로세스를 죽이려면 kill %1라고 하거나 kill 1384라고 하면 됩니다.

Thanks, S.C.

disown

쉘의 활성화 작업 테이블에서 특정 작업을 지워버립니다.

fg, bg

fg 명령어는 백그라운드에서 실행중인 작업을 포그라운드로 돌려 놓습니다. bg 명령어는 중지되어 있던 작업을 백그라운드에서 다시 돌게 합니다. fgbg에 작업 번호가 주어지지 않는다면 현재 돌고 있는 작업에 대해서 동작합니다.

wait

백그라운드로 실행중인 모든 작업이나 옵션으로 주어진 특정 작업 번호나 프로세스 아이디가 끝날 때까지 스크립트 실행을 중단 시킵니다. 자신이 기다리고 있던 명령어의 종료 상태를 리턴합니다.

백그라운드 작업이 끝나기 전에 스크립트가 끝나는 것(무서운 고아 프로세스를 만들어 낼 수 있습니다)을 피하기 위해 wait 명령어를 쓸 수도 있습니다.

예 11-16. 작업을 계속 해 나가기 전에 프로세스가 끝나길 기다리기

#!/bin/bash

ROOT_UID=0   # $UID 가 0인 사용자만이 루트 권한을 갖습니다.
E_NOTROOT=65
E_NOPARAMS=66

if [ "$UID" -ne "$ROOT_UID" ]
then
  echo "이 스크립트는 루트만 실행시킬 수 있습니다."
  # "잘 시간이 지난 것 같은데 꺼지지 그래."
  exit $E_NOTROOT
fi  

if [ -z "$1" ]
then
  echo "사용법: `basename $0` find-string"
  exit $E_NOPARAMS
fi


echo "'locate' 데이타베이스 업데이트중..."
echo "시간이 걸릴 수 있습니다."
updatedb /usr &     # 루트로 실행시켜야 됩니다.

wait
# 'updatedb' 가 끝나기 전까지 이 다음 부분을 실행 시키지 않습니다.
# 아마도 업데이트된 최신 데이타베이스에 
# 여러분의 찾는 파일이 반영돼 있기를 바랄테니까요.

locate $1

# wait 명령어를 쓰면,
# 'updatedb' 가 돌고 있는데 스크립트가 종료되는 최악의 시나리오에서
# 고아 프로세스를 만드는 것을 막아줍니다.

exit 0

wait %1 이나 wait $PPID 처럼 wait에 작업 ID를 인자로 줄 수도 있습니다. 작업 ID 테이블을 참고하세요.

작은 정보: 스크립트에서 어떤 명령어를 백그라운드로 돌리려고 & 를 붙여서 실행시키면 스크립트가 ENTER를 칠 때까지 멈춰 있을 수 있습니다. 명령어가 표준출력으로 쓰기 때문에 생기는 문제처럼 보이는데, 이것 때문에 아주 성가실 수 있습니다.
#!/bin/bash
# test.sh		  

ls -l &
echo "Done."
bash$ ./test.sh
Done.
[bozo@localhost test-scripts]$ total 1
-rwxr-xr-x    1 bozo     bozo           34 Oct 11 15:09 test.sh
               

백그라운드로 돌릴 명령어 다음에 wait를 두면 문제를 해결할 수 있어 보입니다.
#!/bin/bash
# test.sh		  

ls -l &
echo "Done."
wait
bash$ ./test.sh
Done.
[bozo@localhost test-scripts]$ total 1
-rwxr-xr-x    1 bozo     bozo           34 Oct 11 15:09 test.sh
               
명령어의 출력을 아무 파일이나 /dev/null재지향하는 것도 이 문제를 해결할 수 있습니다.

suspend

Control-Z 와 비슷한 효과를 갖고 있지만 이것은 쉘을 suspend 시킵니다(쉘의 부모 프로세스는 적당한 시간이 지나면 실행을 재개할 것입니다).

logout

로그인 쉘을 빠져나가기. 옵션으로 종료 상태를 지정해 줄 수 있습니다.

times

명령어를 실행하는 데 쓰인 시스템 시간에 대한 통계 정보를 다음 형식으로 보여줍니다.
0m0.020s 0m0.020s
제한된 범위의 값만을 보여주기 때문에 쉘 스크립트를 프로파일하거나 벤치마크하는데 쓰이지 않습니다.

kill

적당한 종료 시그널을 주어 프로세스를 강제로 끝내게 합니다(예 13-4 참고).

참고: kill -l이라고 하면 가능한 모든 시그널을 볼 수 있습니다. kill -9은 간단한 kill만으로 죽기를 거부하는 지독한 프로세스를 "확실히 죽여줍니다". 가끔은, kill -15로도 될 때가 있습니다. 부모가 종료된 "좀비 프로세스"는 죽일 수 없지만(이미 죽은 것을 죽일 수는 없습니다), 보통은 init이 이런 상태를 금방 청소해 줄 것입니다.

command

command 명령어 지시어는 "명령어"에 대한 별칭이나 함수 찾기를 하지 않습니다.

참고: 이는 스크립트의 명령어 처리에 영향을 주는 세 가지 지시어중 하나이고, 나머지 두 개의 지시어는 builtinenable입니다.

builtin

builtin BUILTIN_COMMAND라고 치면 "BUILTIN_COMMAND"를 쉘 내장 명령어로 실행 시키면서 잠시 같은 이름을 가진 함수와 외부 시스템 명령어에 대한 기능을 꺼버립니다.

enable

이 명령어는 쉘 내장 명령을 키거나 끄는 역할을 합니다. 예를 들어, enable -n kill이라고 하면 쉘 내장 명령인 kill의 기능을 끄고 다음부터 나오는 모든 kill에 대해서는 /bin/kill을 실행 시킵니다.

-a 옵션을 주면 모든 쉘 내장 명령에 대해 각각이 사용 가능한 지를 보여줍니다. -f filename 옵션은 enable 명령어가 미리 컴파일된 오브젝트 파일에서 공유 라이브러리(DLL) 모듈을 내장 명령으로 로드하도록 해 줍니다. [1].

autoload

이 명령어는 ksh autoloader를 Bash로 포팅한 것입니다. autoload를 함수 선언시에 같이 쓰면, 그 함수가 처음 불릴 경우에 외부 파일에서 로드합니다. [2] 이렇게 하면 시스템 리소스를 절약해 줍니다.

조심할 것은 autoload는 Bash 설치시 기본으로 깔리지 않기 때문에 enable -f(위를 참조)로 로드를 해 주어야 합니다.

표 11-1. 작업 ID(Job Identifiers)

표시
%N[N] 작업 숫자
%SS 문자로 시작하는 작업을 부름(명령어줄)
%?SS 문자를 포함하는 작업을 부름(명령어줄)
%%"현재" 작업(포그라운드에서 중지된 최근 작업이나 백그라운드로 막 돌기 시작한 작업)
%+"현재" 작업(포그라운드에서 중지된 최근 작업이나 백그라운드로 막 돌기 시작한 작업)
%-마지막 작업
$!최근 백그라운드 프로세스

주석

[1]

로드할 수 있는 내장 명령의 C 소스는 보통 /usr/share/doc/bash-?.??/functions 디렉토리에서 찾을 수 있습니다.

enable 명령어의 -f 옵션은 모든 시스템에서 가능하지 않습니다. 주의하세요.

[2]

typeset -fu 라고 해서 autoload와 같은 효과를 가져올 수 있습니다.