다음 이전 차례

3. 외부 명령어들

3.1 PROMPT_COMMAND

배쉬에서는 또 다른 환경 변수 PROMPT_COMMAND가 제공됩니다. 배쉬가 프롬프트를 표시하기 바로 직전에, 정상적인 배쉬 명령어로서, 이 변수의 내용이 실행됩니다.

[21:55:01][giles@nikola:~] PS1="[\u@\h:\w]\$ "
[giles@nikola:~] PROMPT_COMMAND="date +%H%M"
2155
[giles@nikola:~] d
bin   mail
2156
[giles@nikola:~] 

위에서 일어난 일을 말씀드리자면, 이스케잎 시퀀스에서 '\t'를 제외 시켜서, 프 롬프트에 시각이 더 이상 포함되지 않도록 하였읍니다. 그리고나서 'date +%H%M' 를 사용하여 제가 더 좋아하는 형식으로 시각을 표시하도록 하였읍니다. 그렇지만 이번에는 프롬프트와는 서로 다른 줄에 나타났읍니다. 배쉬2.0+ 에서는 'echo -n ...'를 사용하여 잘 정돈할 수 있으며, 아래에서와 같이 작용하지만, 배쉬1.14.7에서는 작동하지 않게 됩니다.: 명백히 프롬프트는 다른 식으로 작성되 고, 아래와 같은 방법은 중복된 문장으로 나타납니다.

2156
[giles@nikola:~] PROMPT_COMMAND="echo -n [$(date +%H%M)]"
[2156][giles@nikola:~]$
[2156][giles@nikola:~]$ d
bin   mail
[2157][giles@nikola:~]$ unset PROMPT_COMMAND
[giles@nikola:~]

'echo -n ...'에 의해 날짜 명령의 출력이 조절되고 뒤에 따르는 '새줄' 문자가 무효 화되어, 프롬프트와 함께 모두 한 줄에 나타나게 됩니다. 마지막에서, 'unset' 명령 에 의해 환경 변수 PROMPT_COMMAND가 제거되었읍니다. 명령어 대치를 위해 $() 양식이 사용된 것에 유의하십시오: 즉,

$(date +%H%M)

는 "여기에다 'date +%H%M' 명령으로 부터의 출력으로 대치하시오" 라는 의미 입니다. 이것은 배쉬2.0+ 에서 작동합니다. 1.14.7 이전의 몇몇 구 버전의 배쉬 에서는 역인용 부호(backquates)(`date +%H%M`)가 필요할 수가 있읍니다. 역인용 부호는 배쉬2.0+ 에서도 사용 가능하지만, $() 양식을 더 선호 함에 따라 사라져 가고 있으며, $() 양식이 자리를 굳혀 가고 있읍니다. 이 문서에서도 새 양식으로 계속 될 것 입니다. 만약 이전 버전을 사용하고 계시다면, $() 이 나타나는 곳에서 역인용 부호로 대치하면 될 것입니다. 만약, 명령어 대치가 이스케잎 처리되어 있다면 (즉, \$(command) ), basckslash('\')를 사용하여 양쪽의 역인용 부호를 이스케잎 처리 하십시오(즉, \'command\' ).

3.2 프롬프트에서의 외부 명령어들

프롬프트에서 정상적인 리눅스 명령의 출력 결과도 역시 사용 가능합니다. 너무 많은 것들을 프롬프트에 포함하기를 원하지는 않을 것입니다. 그렇지 않으면 프롬프트가 너무 길어질 테니까요. 또한, 신속히 처리되는 명령어를 사용하기를 원할 것입니다. 왜냐하면, 스크린에 프롬프트가 나타날 때 마다 그명령어들이 수행되어야 하고, 작업을 하는 동안에 프롬프트가 나타나는 것이 성가시게 될 수도 있기 때문입니다.( 이전의 예와 아주 유사한 결과이지만, 배쉬1.14.7에서도 작동합니다)

[21:58:33][giles@nikola:~]$ PS1="[\$(date +%H%M)][\u@\h:\w]\$ "
[2159][giles@nikola:~]$ ls
bin   mail
[2200][giles@nikola:~]$

명령어 대치의 달러기호('$') 앞의 backslash에 주의하는 것이 중요합니다. 그것이 없으면 외부 명령어는 정확하게 한번만 수행됩니다: PS1 변수가 읽어 들여질 때 마다. 이 프롬프트의 경우에는, 프롬프트의 길이가 얼마나 되는지 상관 없이 동시에 표시될 것이라는 것을 의미합니다. backslash('\')에 의해 $()의 내용이 쉘 해석으로 부터 보호되어, "date" 명령이 새로운 프롬프트 가 생성될 때 마다 수행됩니다.

리눅스에는 많은 종류의, date, grep, 또는 wc 와 같은 조그마한 유틸리티 프로그램들이 부수되어 있어, 데이타를 처리할 수 있도록 합니다. 만약, 이들 프로그램들의 아주 복잡한 조합을 생성해서 프롬프트 안에 넣고자 하신 다면, 여러분 자신의 쉘 스크립트를 작성한 다음, 프롬프트에서 그것을 불러 들이는 방법이 더 쉬울 수 있읍니다. 적절한 때에 쉘 변수들이 풀어지도록 하기 위해 쉘 스크립트 내에서 자주 이스케잎 시퀀스들이 요구됩니다(위에서 보여진 날짜 명령어와 같이): 이것은 프롬프트 PS1 라인 내에서 한 단계 높은 수준으로 올라 가는 것이며, 쉘 스크립트를 생성하여 회피하는 방법은 아주 훌륭한 아이디어입니다.

프롬프트 내에서 사용되는 조그만 쉘 스크립트 예제가 아래에서 주어집니다.

#!/bin/bash
#     lsbytesum - sum the number of bytes in a directory listing
TotalBytes=0
for Bytes in $(ls -l | grep "^-" | cut -c30-41)
do
    let TotalBytes=$TotalBytes+$Bytes
done
TotalMeg=$(echo -e "scale=3 \n$TotalBytes/1048576 \nquit" | bc)
echo -n "$TotalMeg"

저는 이것을 때에 따라서 함수로(훨씬 효율적이지만-불행하게도 함수에 대한 자세한 설명은 이 문서의 범위 밖입니다), 또는 경로에 포함되어 있는 ' /bin' 디랙토리에 있는 쉘 스크립트로 보관했읍니다. 프롬프트에 사용되어 아래와 같은 결과가 됩니다.

[2158][giles@nikola:~]$ PS1="[\u@\h:\w (\$(lsbytesum) Mb)]\$ "
[giles@nikola:~ (0 Mb)]$ cd /bin
[giles@nikola:/bin (4.498 Mb)]$

3.3 프롬프트에서 필요한 그밖의 것들

대부분의 제가 만든 프롬프트에는 시각과 현재 디랙토리의 이름이 포함되어 있다는 것을 알 수 있읍니다. 여기에다가, 소형이지만 효과적인 Dan씨가 만든 프롬프트를 넣고자 합니다.

[giles@nikola:~]$ cur_tty=$(tty | sed -e "s/.*tty\(.*\)/\1/")
[giles@nikola:~]$ echo $cur_tty
p4
[giles@nikola:~]$ PS1="\!,$cur_tty,\$?\$ "
1095,p4,0$ 

디랙토리 경로를 바꿈에 따라서 프롬프트의 크기가 갑작스럽게 바뀔 수 있기 때문에 Dan씨는 프롬프트에 현재의 디랙토리가 표시되는 것을 좋아하지 않읍니다. 그래서 그는 디랙토리의 자취를 그의 머리속에 기억합니다(또는 "pwd"를 치기도 합니다.) Dan씨는 cash과 tcsh로 유닉스를 익혔기 때문에, 그는 명령어 history를 광범위 하게 사용하고 있으며(우리들의 대부분은 배쉬를 쓴다고 믿기에 그럴 필요가 없지만), 그래서, 그의 프롬프트의 첫번째 항목은 명령어 history 번호입니다. 두번째 항목은 tty의 중요 문자들 입니다("tty"의 출력을 'sed'로 모읍니다). 세번째 항은 마지막 command/pipeline의 exit 값입니다(note that this is rendered useless by any command executed within the prompt - you could work around that by capturing it to a variable and playing it back, though). 마지막으로, "\$"은 일반 사용자에게는 달러 기호를 나타내고, 사용자가 루트일 경우에는 해쉬 표시("#") 를 나타냅니다.

3.4 배쉬 환경과 함수들

앞에서 언급된 바와 같이, PS1, PS2, PS3, PS4 그리고 PROMPT_COMMAND 들은 모두 배쉬 환경으로 저장되어 있읍니다. DOS에 익숙한 분들은 아주 큰 덩어리의 정보를 환경으로 넘기는데에 대하여 두려운 생각을 가질 것입니다. 왜냐하면 DOS의 환경은 조그마했 으며, 잘 확장하지도 않았기 때문입니다. 환경에 넣을 수 있고 넣어야만 하는 것들에 대해서 실제적인 제약이 있을지도 모르지만, 그것들이 뭐가 될지도 모르고, 여기에서 는 DOS 사용자들에게 익숙한 그런 환경보다는 규모에 있어서 아마 몇배나 훨씬 더 큰 것에 대하여 이야기를 하고 있읍니다. 우리의 Dan씨가 말합니다:

"제가 사용하는 쉘에는, 62개의 알리아스와 25개의 함수가 있읍니다. 기계에서 직접 사용할 경우에, 어떤 것이 단독적으로 필요하고 bash에서 손으로 쉽게 씌어질 수 으면, 그것을 쉘 함수로 만든다는 것이 제일 첫번째 규칙입니다(알리아스로 쉽게 표현 할 수 없다는 가정하에서). 만약 메모리에 대해서 걱정하는 사람들이 있다면, 그들은 bash를 사용할 필요가 없읍니다. Bash는 저의 리눅서 기계에서 실행되는 가장 큰 프로그램 중의 하나입니다(Oracle을 제외하고). 때때로 'top'을 실행 시켜서 사용 메모리별로 분류하기 위해 'M'을 눌러 보세요-목록에서 bash가 얼마나 윗쪽에 가까이 있는지 살펴 보세요. 윽, sendmail보다도 더 덩치가 크군요! 그들 더러 가서 ash나 또는 다른 것들을 구하라고 하세요"

아마도 그는 그 작업을 하려고 하는 날에만 콘솔을 사용하지않나 추측합니다:X나 X응용 프로그램을 실행시키면, 배쉬보다 더 큰 것들이 많이 있읍니다. 그렇지만, 아이디어는 동일합니다:환경이라는 것은 사용되어야 하는 것이고, 그것이 차고 넘치는 것은 걱정할 필요가 없읍니다.

제가 이렇게 말할 때(너무 단순화 시켰다는 것에 대해서) 유닉스 구루들로 부터 책망 을 받을 각오를 하지만, 함수들이란 기본적으로 효율성을 위해 환경으로 적재되는 조그만 쉘 스크립트들입니다. Dan씨의 말을 다시 인용합니다:"쉘 함수들은 가능한 만큼 효율화 한것입니다. It is the approximate equivalent of sourcing a bash/bourne shell script save that no file I/O need be done as the function is already in memory. 쉘 함수들은 전형적으로, 그것들이 최초의 쉘에서만 필요한지 또는 하부의 쉘에서도 요구되는가에 따라, [.bashrc 또는 .bash_profile]로 부터 적재됩니다. 쉘 스크립트 하나를 실행 시켜서 이것을 대비해 보십시오: 쉘이 분기하여, 자식 프로쎄스가 exec 를 수행하고, potentially 경로가 찾아지고, 커널이 파일을 열고 그 파일을 어떻게 실행할지 결정하기위해 충분한 바이트를 검사하며, 쉘 스크립트인 경우 쉘이 그 스크립트의 이름을 변수로 하여 시작하여야 하며, 그 다음에 파일을 열고, 읽고 그 문장을 수행합니다. 쉘 함수와 비교하여, 문장을 수행하는 것을 빼고는 다른 것들은 불필요한 것으로 간주됩니다."


다음 이전 차례