8. 효율적인 작업을 위해서

다른 여러가지 훌륭한 언어(C, Perl, Python)가 있음에도 불구하고 여전히 쉘을 사용하는 이유는 효율적인 작업을 위해서 일것이다. bash 는 사용자가 중복시간을 줄이고, 작업을 빠르고 효율적으로 할수 있도록 하기 위해서 history, 명령어치환 과 같은 여러가지 기능들을 제공한다.

8.1. 환경변수

bash(다른 쉘도 마찬가지)은 환경변수라는걸 사용한다. 환경변수는 쉘이 운용되는데 필요한 여러가지 값들을 가지고 있다. 대표적인 예로 SHELL 변수가 있다. 이변수에는 현재 로그인 유저가 사용하고 있는 쉘이 어떤건지에 대한 정보를 가지고 있다. 여러분이 현재 사용하는 쉘이 어떤건지 알고 싶다면 다음과 같이 하면된다.
	[yundream@localhost yundream]$ echo $SHELL
	/bin/bash
		
이밖에도 PATH, USER, TERM, PWD 등과 같은 많은 환경변수를 가지고 있다.

환경변수를 세팅하기 위해서는 export 라는 쉘 명령어를 사용한다.
	[yundream@localhost yundream]$ export MY_NAME="yundream"
	[yundream@localhost yundream]$ echo $MY_NAME
	yundream
		
현재 설정되어 있는 모든 환경변수를 보기 위해서는 set 명령을 이용하면 된다. 이렇게 해서 설정된 환경변수는 현재 쉘에서 실행되는 모든 자식 프로세스에 상속 되게 된다.

8.2. history

history 는 이전에 내렸던 명령을 기억해서 다시 써먹으려고 할때 유용하다. 터미널에서 history 명령을 내림으로써 이전에 실행했던 명령어의 목록을 확인할수 있다.
	[yundream@localhost yundream]$ history
	    1   micq 
		2   exit
		3   make clean
		...
		454 vi /home/httpd/cont/httpd.conf
		455 history
			
히스토리가 저장되는 크기는 환경변수인 HISTSIZE 에 저장된다. 보통은 1000 라인정도로 세팅되어 있다. 히스토리에서 원하는 명령을 사용하고 싶을때는 "!n" 을 사용하면 된다. "n" 은 히스토리 번호이다. 즉 make clean 을 다시 실행하고 싶다면 "!3" 하면 된다.

"!" 는 히스토리 기능을 사용하기 위한 쉘 예약어이다. 이걸 사용하면 작업을 편하게 할수 있다. "!(문자열)" 하게 되면, 히스토리 목록중에서 (문자열)로 시작되는 가장 최근에 실행된 히스토리의 명령어를 불러와서 실행하게 된다. 위에서 454 번의 명령을 다시 실행하고 싶다면, !vi 하면 된다. 물론 !v 해도 관계없다.

히스토리는 grep 과 조합되어서 자주 사용한다.
	[root@localhost /root]# history | grep configure
	    8  ./configure --with-apache=../apache-1.3.22 
	   13  ./configure 
	   14  ./configure i686-linux
	   15  ./configure --help
	[root@localhost /root]# !8
	./configure --with-apache=../apache-1.3.22
			

8.3. 최근명령어 치환

아래와 같은 상황을 가정해보자
	[root@localhost /]# vp file1 file2
	bash: vp: command not found
			
사실은 file1 을 file2 로 복사하는 작업을 하길 원했으나, cp 를 vp 로 치는 오류를 범했다. 이를 정정하기 위해서는 처음부터 다시치거나, 자판을 "v" 까지 움직 여서 이를 "c"로 교체 해야 할것이다. 이럴경우 "^"를 사용하면 작업을 좀더 빨리 할수 있다.
	[root@localhost /]# ^v^c
	cp file1 file2
			
"^[원본문자열]^[바뀔문자열]" 의 형식으로 사용하면, 가장 최근의 명령에서 원본문자열을 바뀔문자열로 치환하여 명령을 다시 실행하게 된다.

8.4. Prompt

Prompt 란 쉘이 사용자의 입력을 기다리고 있음을 유저에게 알려주기 위해서 사용한다. Prompt 를 잘 사용하게 되면 여러분이 어떤 호스트 에서 작업을 하는지, 혹은 몇시인지, 어떤 디렉토리에서 작업하고 있는지 등의 작업정보등을 얻을수 있다.

프롬프트 정보는 환경변수 PS1 에 저장된다. echo $PS1 해 보면 현재 설정된 프롬프트 정보를 볼수 있다. bash 는 효율적인 프롬프트 정보를 보여주기 위해서 몇개의 특수 문자 들을 제공하고 있다.

표 2. Prompt 예약어

\t현재 시간을 HH:MM:SS 형식으로 보여준다.
\d날자를 "요일 월 일" 형식으로 보여준다.
\s쉘의 이름을 보여준다.
\w현재 작업디렉토리를 완전경로로 보여준다.
\W현재 작업디렉토리의 이름을 보여준다.
\u현재 사용자의 사용자명
\h호스트이름
\!이 명령의 히스토리 번호
\nnn8진수 nnn에 해당하는 문자
\[비출력문자의 시퀀스를 시작한다.
\]비출력문자의 시퀀스를 마친다.
간단한 예를 들어보자. 우리는 Prompt 상에 현재 시간과, 작업디렉토리 정보를 보여주길 원한다. 이럴때는 아래와 같이 하면 된다.
	[root@localhost httpd]# export PS1="[\t \W]# "
	[17:40:37 html]# echo "성공적으로 바꼈군요" 
			

8.5. Prompt 전에 명령 실행시키기

이렇게 해서 프롬프트를 변경시키는방법을 알았다. 그런데, 어떤 한텀 의 경우 한텀의 타이틀바 제목이 시시각각 바뀌는것을 본적이 있을 것이다. 이건 어떻게 하는것일까. ?

이건 bash 쉘의 환경변수인 PROMPT_COMMAND 를 사용하여 가능하다. PROMPT_COMMAND 에는 특정 명령어(스트립트 혹은 실행파일)가 값으로 들어가 있는데, 사용자에게 프롬프트가 떨어지기 전에 변수에 있는 명령이 실행된다.
	[root@localhost /root]# export PROMPT_COMMAND="date"
	월 11월 19 17:51:03 KST 2001
	[root@localhost /root]# echo "hello world"
	hello world
	월 11월 19 17:51:19 KST 2001
	[root@localhost /root]# 
			
위의 예에서 보다시피 사용자 프롬프트가 떨어질때 마다, 그전에 "date" 명령이 실행됨을 알수 있다. 이 명령을 약간 변경하면 타이틀바가 그때그때 바뀌도록 설정 할수 있다.
	[root@localhost /home]# export PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
			
위의 경우 디렉토리가 변경될때 마다 작업디렉토리가 타이틀바에 표시 가된다. 위의 내용을 /etc/bashrc 정도에 입력해 놓으면 창을 띄울때 마다 환경변수의 내용이 적용될것이다.

하지만 단순히 사용자에게 시각적으로 그럴듯하게 보여주는것 외에도 PROMPT_COMMAND 를 응용하면 좀더 다양한 일들을 할수 있다. 다음장에서 이에 대해서 간단하지만 유용한 한가지 예를 들어 보도록 하겠다.

8.6. PROMPT_COMMAND 를 이용한 사용자 명령어 추적

요즘 컴터업계 최대의 화두는 "보안"이다. 이런 대세에 맞추어서 사용자가 현재 무슨 명령을 사용중에 있는지 실시간으로 확인할수 있는 간단한 보안 프로그램? 을 작성해보도록 하겠다.

보통 이러한 사용자 명령을 실시간으로 추적하는 프로그램을 보안쉘 이라고 한다. - 물론 실지 보안쉘에는 이외에도, 파일보안, 디렉토리 보안, 프로세스보안 등과 같은 다양한 기능이 들어가지만 여기서는 사용자의 작업내용을 실시간으로 확인할수 있는 기능만 구현하겠다 - 보통 보안쉘을 만드는데는 많은 시간과 인내심이 필요하지만, 쉘의 특징을 조금만 알고 있다면, 시간과 노력을 단축시킬수가 있다.

PROMPT_COMMAND 를 이용하는 방법은 매우 간단하다. 사용자의 프롬프트가 떨어졌을때, 사용자의 이름, 사용자의 가장 최근의 명령어등을 가져와서 이를 파일로 만들거나 소켓을 통해서, 관리자에게 통보하도록 하면 된다. 쉘에서는 물론 history라는걸 제공하긴 하지만, history 는 실시간이 아니다. 일단은 쉘의 메모리에서 관리하고 있다가, 로그아웃 하면 그때 파일로 저장이 된다. 즉 로그아웃 하기 전까지는 무슨일을 하는지 통 알수가 없게 된다. 그리고 history 명령을 이용해서 편집 가능하다. 다음과 같은이름으로 moniter.sh 란 간단한 스크립트 파일을 작성한다.
	LAST_COMMAND=`tail -1 /root/dump`
	CURRENT_COMMAND=`history 1`

	if [ "$LAST_COMMAND" != "$CURRENT_COMMAND" ]
	then
		echo "$CURRENT_COMMAND" >> /root/dump
	fi
			
위의 스크립트를 적당한 디렉토리에 복사한다음에, 각 사용자가 로그인할때 환경변수로 초기화 시키면 된다.
	export PROMPT_COMMAND="/usr/bin/moniter.sh"
			
물론 위의 프로그램에는 여러가지 부족한점이 많다. 마지막 명령이 화일로 저장되며, 또한 사용자가 쉘의 특성을 잘알고 있고, 여기에 주의를 기울인다면 환경변수를 분석해서 이를 조작할수 있다. 이는 여러가지 방법을 통해서 해결할수 있지만, 이는 쉘스크립팅의 범위를 벗어나는 것임으로, 간단히 이러한 일을 할수도 있다라는 것만 이해해 두기로 하자. 이 글을 읽는 여러분이 좋은 방법을 생각해 보기 바란다. (물론 가장 좋은 방법은 쉘 쏘쓰를 수정하는 거다. 생각만큼 복잡하지 않으니 연구해 보시길..)