· KLDP.org · KLDP.net · KLDP Wiki · KLDP BBS ·
Bash Prog Intro Howto

Bash Programming Introduction Howto

Mike G mikkey at dyamo.com.ar

Thu Jul 27 09:36:18 ART 2000

이 글은 당신이 초중급 셸 스크립트 프로그래밍을 시작하는 것을 돕고자 한다. 고도의 문서화를 하려고 하는 게 아니다(제목을 보라). 나는 전문가도 고급 셸 프로그래머도 아니다. 다는 내가 좀 더 배웠고 다른 사람들에게 쓸모가 있을 것이기에 이 글을 쓰기로 결정했다. 어떤 피드백도 - 특히 패치 형태 - 환영한다.


1. 소개

1.2. 요구사항

GNU/Linux 명령행에 익숙하고, 기본 프로그램개념이 있다면 도움이 될 것이다. 이 글은 프로그래밍의 소개가 아니므로, 많은 기본 개념을 설명한다(적어도 시도한다)

1.3. 이 문서의 사용

이 문서는 다음 상황에 쓸모 있게 하려 하였다.
  • 당신이 프로그램에 관해 개념이 있고 당신이 어떤 셸 스크립트를 시작하기를 원한다.
  • 당신은 셸 프로그래밍에 대해 모호한 개념을 가지고 있고 어떤 참고자료를 원한다.
  • 당신은 셸 스크립트와 당신 자신의 셸 스크립트를 작성하기 시작하는 것에 대한 의견을 보기를 원한다.
  • 당신은 DOS / Windows 로 부터 이주하려고 하거나 이주했고, 일괄처리를 만들기를 원한다.
  • 당신은 완전한 컴맹이고 가능한한 모든 하우투를 읽으려고 한다.

2. 매우 간단한 스크립트

2.1. 전통적인 hello world 스트립트

#!/bin/bash
echo Hello World
이 스크립트는 딱 두 줄로 되어 있다. 첫 줄은 프로그램이 파일을 실행시키기 위해 사용할 시스템을 가리킨다.

둘째 줄은 이 스크립트에 의해 수행되는 행동인데, 그것은 터미널에 'Hello World'를 출력한다.

만약 당신이 ./hello.sh: Command not found. 와 같은 것을 보게 된다면 아마도 첫 줄이 잘못되었을 것일텐데, bash가 어디 있는지에 대해 또는 어떻게 당신이 이 줄을 써야 하는지 보기 위해 'bash를 찾는 것'을 하게 될 것이다.

2.2. 매우 간단한 백업 스크립트

#!/bin/bash          
tar -cZf /var/my-backup.tgz /home/me/
이 스크립트에서는 터미널에 메시지를 출력하는 대신 사용자 홈디렉토리의 타르볼을 만든다. 이것은 사용하려고 하는 게 아니고, 좀더 쓸모 있는 백업 스크립트가 이 문서에서 나중에 나온다.

3. 리디렉션의 모든 것

3.1. 이론과 빠른 참조

파일 지시자는 stdin, stdout, stderr 세 개가 있다.

기본적으로 당신은

  1. stdout에서 파일로
  2. stderr에서 파일로
  3. stdout에서 stderr로
  4. stderr에서 stdout로
  5. stderr와 stdout 에서 파일로
  6. stderr와 stdout 에서 stdout로
  7. stderr와 stdout 에서 stderr로
리디렉트할 수 있다.

1은 stdout을 2는 stderr를 나타낸다.

이것을 보기 위한 작은 주석: less 명령어로 당신은stdout (이것은 버퍼에 남음) 과 stderr가 화면에 출력되는 것을 볼 것이지만, 버퍼를 검색하려고 시도하면 지워진다.

3.2. 예: stdout 에서 file

이것은 프로그램의 출력을 파일에 쓸 것이다.
ls -l > ls-l.txt
여기서 ls-l.txt 이라는 파일이 생성될 것이고, 그 파일은 당신이 ls -l를 실행했을 때 화면에 보게 되는 내용을 포함할 것이다.

3.3. 예: stderr 에서 file


이것은 프로그램의 stderr 출력을 파일에 쓸 것이다.
grep da * 2> grep-errors.txt
여기서 'grep-errors.txt'이라는 파일이 생성되고 당신은 'grep da *'명령의 stderr 출력 부분을 볼 것이다.

3.4. 예: stdout 에서 stderr

이것은 프로그램의 stderr출력을 stdout대신 같은 파일지시자에 쓸 것이다.
grep da * 1>&2 
여기서, 명령의 stdout 부분은 stderr로 보내지고, 당신은 다른 방법을 알게 될 것이다.

3.5. 예: stderr 에서 stdout

이것은 프로그램의 stderr출력글 stdout 대신 같은 파일지시자에 쓸 것이다.
grep * 2>&1
여기서 이 명령의 stderr 부분은 stdout 로 보내지고, 당신이 less로 파이프하면, 당신은 보통 '사라지는'(그것들이 stderr에 써진 것 처럼) 줄이 현재는 유지되는 것을 볼 것이다.(왜냐면 그것은 stdout에 있으므로)

3.6. 예: stderr 와 stdout 에서 file

이것은 프로그램의 모든 출력을 파일에 저장할 것이다. 이것은 당신이 절대로 조용히 명령이 진행되기를 원하면 때때로 cron 요소에 적합하다.
rm -f $(find / -name core) &> /dev/null 
이것은(cron 요소에서 생각하면) 모든 디렉토리의 core 라는 모른 파일을 지울 것이다.

당신은 당신이 그 출력을 지운다면 어떤 명령이 실행되는지 분명히 알고 있어야 한다.

4. 파이프

이 절은 파이프를 어떻게 쓰는지 매우 간단하고 실용적인 방법을 설명하고, 왜 당신이 그것을 원할 것인지 설명할 것이다.

4.1. 그것은 무엇인가 왜 당신은 그것을 사용하기를 원할 것인가

파이프는 당신이 프로그램의 출력을 다른 프로그램의 입력으로 사용하게 한다.

4.2. 예: sed와 간단한 파이프

이것은 파이프를 사용하는 간단한 방법이다.
ls -l | sed -e "s/[aeio]/u/g"   
여기서, 아래의 상황이 발생한다. 처음에 ls -l 명령이 실행되고, 그것의 출력이 인쇄되는 대신 프로그램에 보내진다(파이프된다). 결국, 그것이 해야 하는 것을 인쇄된다.

4.3. 예: 다른 ls -l *.txt

아마, 이것은 ls -l *.txt 을 실행하는 좀더 다른 방법일 것이지만, 파이프를 묘사하려는 것이지 이런 리스팅 문제를 풀려는 것이 아니다.
ls -l | grep "\.txt$"
여기서, ls -l 프로그램의 출력이 grep 프로그램에 보내져 결국 정규표현식 "\.txt$" 에 맞는 행을 출력할 것이다.

5. 변수

당신은 다른 프로그램 언어처럼 변수를 사용할 수 있다. 자료형은 없다. bash의 변수는 숫자, 문자, 문자열을 포함할 수 있다.

변수를 선언할 필요는 없으며, 값을 참조에 할당하기만 하면 변수를 생성한다.

5.1. 예: 변수를 사용한 Hello World!

#!/bin/bash
STR="Hello World!"
echo $STR

둘 째 줄은 STR이라는 변수를 생성하고 "Hello World!"을 할당한다. 그러면 이 변수의 값은 앞에 $를 붙여서 되찾을 수 있다. 만약 $ 기호를 사용하지 않는다면, 그 프로그램의 출력은 다를 것이고, 거의 당신이 원하는 바가 아닐 것이다.

5.2. 예: 매우 간단한 백업 스크립트(조금 나아진 것)

#!/bin/bash          
OF=/var/my-backup-$(date +%Y%m%d).tgz
tar -cZf $OF /home/me/
이 스크립트는 다른 것을 도입한다. 우선, 둘째 줄의 변수 생성과 할당에 익숙해져야 한다. 식 '$(date +%Y%m%d)'을 주목하라. 스크립트를 실행하면 괄호 안에 있는 명령을 실행하고 출력을 잡을 것이다.

이 스크립트 안에서, 출력 파일 이름은 매일 달라질 것이고, date 명령의 형식 변환(+%Y%m%d) 때문이다.

예가 더 있다.

echo ls

echo $(ls)

5.3. 지역 변수

지역 변수는 local 키워드를 사용하여 생성할 수 있다.
#!/bin/bash
HELLO=Hello 
function hello {
  local HELLO=World
  echo $HELLO
}
echo $HELLO
hello
echo $HELLO

이 예는 어떻게 지역 변수를 사용하는지 보여준다.

6. 조건문

조건문은 어떤 행동을 수행할지 하지 않을지 결정하게 하고, 이 결정은 식에 의해 이루어진다.

6.1. 시시한 이론

조건문은 여러 형식이 있다. 가장 기본적인 형식은 if 식 then 문장인데 여기서 문장은 식이 참일 때만 실행된다. '2<1'은 거짓으로 평가 되고 '2>1'은 참으로 평가된다.

조건문은 다음과 같이 다른 형식이 될 수도 있다. if 식 then 문장1 else 문장2. 여기서 식이 참이면 문장1이 실행되고, 그렇지 않으면 문장2가 실행된다.

또 다른 형식의 조건문은 if 식1 then 문장1 else if 식2 then 문장2 else 문장3 이다. 이 형식에서는 else if 식2 then 문장2 가 추가된 것 뿐인데, 그것은 식2가 참일 때 문장2를 실행하게 한다. 나머지는 당신이 생각하는 것과 같다.

구문에 대한 말:

bash에서 if 구문의 기본은 아래와 같다.
if [ 식 ]; 
then 
식이 참일 때의 코드
fi

6.2. 예: 기본 조건문 if ... then

#!/bin/bash
if [ "foo" = "foo" ]; then
  echo expression evaluated as true
fi
이 코드는 괄호 안의 식이 참이면 then 다음에서 fi 전까지의 코드를 실행한다.

6.3. 예: 기본 조건문 if ... then ... else

#!/bin/bash
if [ "foo" = "foo" ]; then
  echo expression evaluated as true
else
  echo expression evaluated as false
fi

6.4. 변수를 가진 조건문

#!/bin/bash
T1="foo"
T2="bar"
if [ "$T1" = "$T2" ]; then
  echo expression evaluated as true
else
  echo expression evaluated as false
fi

7. for, while, until

이 절에서는 for, while, until 에 대해 찾을 수 있다.

for는 다른 프로그래밍 언어와 다르다. 기본적으로, 한 문자열 안에 있는 단어의 열을 반복하게 한다.

while은 만약 제어 식이 참일 때 코드를 실행하고, 거짓일 때(또는 실행되는 코드에서 명시적인 break를 찾았을 때)는 끝난다.

until은 제어코드가 거짓으로 평가 되는 동안 실행돠는 것만 제외하고 while과 거의 같다.

만약 당신이 while과 until이 매우 비슷하다는 걸 눈치챘다면 당신은 제대로 본 것이다.

7.1. for 예

#!/bin/bash
for i in $( ls ); do
  echo item: $i
done
둘째 줄에서 i를 변수로 선언하고 $(ls)안에 포함된 다른 값을 얻는다.

세째 줄은 필요하면 더 길어질 수도 있다. 즉 done 이전에 더 많은 줄이 있을 수 있다.

done 은 $i의 값이 사용되는 것이 끝났고 $i가 새로운 값을 얻을 수 있음을 가리킨다.

7.2. C 비슷한 for

fiesh가 이 형식을 더하는 것을 제안했다. C/Perl 과 비슷한 for 이다.
#!/bin/bash
for i in `seq 1 10`;
do
  echo $i
done

7.3. while 예

#!/bin/bash 
COUNTER=0
while [  $COUNTER -lt 10 ]; do
  echo The counter is $COUNTER
  let COUNTER=COUNTER+1 
done
이 스크립트는 잘 알려진(C, Pascal, perl, 등) for 구조를 흉내낸다.

7.4. until 예

#!/bin/bash 
COUNTER=20
until [  $COUNTER -lt 10 ]; do
  echo COUNTER $COUNTER
  let COUNTER-=1
done

8. 함수


거의 모든 프로그램 언어에서 처럼, 당신은 좀더 논리적인 방법으로 코드의 조각들을 묶거나 재귀의 기술을 실행하기 위해 함수를 사용할 수 있다.

함수를 선언하는 것은 대략 내_함수 {내_코드} 으로 쓰는 것이다.

함수를 호출하는 것은 다른 프로그램처럼 당신이 그 이름을 쓰는 것이다.

8.1. 함수 예

#!/bin/bash 
function quit {
  exit
}
function hello {
  echo Hello!
}
hello
quit
echo foo 
둘째 - 네째 줄은 quit 함수를 포함한다. 다섯째 - 일곱째줄은 hello 함수를 포함한다. 만약 이 스크립트가 무엇을 하는지 잘 모르겠으면 꼭 해 보시오.

함수는 특정한 순서로 선언될 필요는 없다.

스크립트를 실행시키면 우선 다음을 주목하라. 함수 hello가 호출되면 quit 함수가 호출되고, 프로그램은 열째 줄에 도달하지 못한다.

8.2. 매개변수를 가진 함수 예

#!/bin/bash 
function quit {
  exit
}  
function e {
  echo $1 
}  
e Hello
e World
quit
echo foo 
이 스크립트는 첫번째 것과 거의 같다. 주된 차이는 함수 e이다. 이 함수는 받은 매개변수를 출력한다. 함수에서는 매개변수는 스크립트에 주어진 매개변수와 같은 방법으로 다루어진다.

9. 사용자 인터페이스

9.1. 간단한 메뉴를 위한 select 사용

#!/bin/bash
OPTIONS="Hello Quit"
select opt in $OPTIONS; do
  if [ "$opt" = "Quit" ]; then
    echo done
    exit
  elif [ "$opt" = "Hello" ]; then
    echo Hello World
  else
    clear
    echo bad option
  fi
done
당신이 이 스크립트를 실행하면 이것이 테스트기반메뉴에 대한 프로그래며의 꿈이라는 것을 볼 것이다. 당신은 이것이 단순히 $OPTIONS 안의 각각의 단어를 도는 것만이 아니라는 것 말고는 for구조와 비슷하다. 이것은 사용자 응답을 기다린다.

9.2. 명령행 사용하기

#!/bin/bash        
if [ -z "$1" ]; then 
  echo usage: $0 directory
  exit
fi
SRCD=$1
TGTD="/var/backups/"
OF=home-$(date +%Y%m%d).tgz
tar -cZf $TGTD$OF $SRCD
이 스크립트가 하는 것은 당신에게 명확할 것이다. 첫번째 조건문의 식은 프로그램이 매개변수($1)을 받았는지 체크하고 받지 않았으면 끝내고, 사용자에게 간단한 사용법 메시지를 보여준다. 나머지 부분은 명확하다.

10. 기타

10.1. read로 사용자 입력 읽기

여러 경우에 당신은 사용자가 어떤 입력에 응답하기를 원할것이고, 이것을 수행하는 방법은 여러가지가 있다. 그 중 한 방법이 이것이다.
#!/bin/bash
echo Please, enter your name
read NAME
echo "Hi $NAME!"

변화를 주어 여러개의 값은 얻을 수 있고 이 예제가 그것을 명확히 할 것이다.
#!/bin/bash
echo Please, enter your firstname and lastname
read FN LN 
echo "Hi! $LN, $FN !"

10.2. 산술 평가

명령행(또는 셸)에서 이것을 시도해 보라.
echo 1 + 1 

당신이 2를 기대했다면 기대가 어긋날 것이다. 당신은 BASH가 어떤 수를 계산하기를 원한다면 어떻게 해야 할까? 답이 이것이다.
echo $((1+1)) 

이것은 좀 더 논리적인 출력을 만들 것이다. 이것은 산술식을 계산한 것이다. 당신은 이것을 이렇게 할 수 있다.
echo $[1+1] 

당신이 분수를 사용하기 원한다면, 또는 수학 또는 당신이 그것을 원하기만 한다면, 당신은 산술식을 계산하기 위해 bc를 사용할 수 있다.

만약 echo $[3/4]을 실행한다면, 0을 반환할 것이다. 왜냐하면, bash는 답할때 정수만을 사용하기 때문이다. echo 3/4|bc -l을 실행하면 0.75를 반환할 것이다.

10.3. bash 찾기

mike로부터의 메시지에서 (Thanks to 를 보라)

당신은 항상 #!/bin/bash .. 를 사용했다.어디에 bash가 있는지 찾는 방법을 보여주었으면 한다.

'locate bash'를 권장하지만, 모든 기계가 locate를 가지고 있는 건 아니다.

/ 디렉토리에서 'find ./ -name bash' 를 하면 대개의 경우 될 것이다.

점검해볼 위치 추천

ls -l /bin/bash

ls -l /sbin/bash

ls -l /usr/local/bin/bash

ls -l /usr/bin/bash

ls -l /usr/sbin/bash

ls -l /usr/local/sbin/bash

'which bash'를 시도해 볼 수도 있다.

10.4. 프로그램의 반환값 얻기

bash에서, 프로그램의 반환값은 특정한 변수 $? 에 저장된다.

이것은 어떻게 프로그램의 반환값을 어떻게 잡는지 묘사한다. 나는 디렉토리 데이터가 존재하지 않는다고 가정했다.(이 또한 mike가 제안했다)
#!/bin/bash
cd /dada &> /dev/null
echo rv: $?
cd $(pwd) &> /dev/null
echo rv: $?

10.5. 명령 출력 잡기


이 작은 스크립트는 모든 데이터베이스의 테이블은 보여준다.(MySQL이 설치되었다고 가정한다). 또한, 올바른 사용자와 패스워드를 사용하여'mysql'을 사용한다고 가정한다.
#!/bin/bash
DBS=`mysql -uroot  -e"show databases"`
for b in $DBS ;
do
  mysql -uroot -e"show tables from $b"
done

10.6. 여러 소스파일

당신은 여러개의 명령소스로 여러개의 파일을 사용할 수 있다.

11. Tables

11.1. 문자열 비교 연산자

(1) s1 = s2

(2) s1 != s2

(3) s1 < s2

(4) s1 > s2

(5) -n s1

(6) -z s1


(1) s1 matches s2

(2) s1 does not match s2

(3) TO-DO

(4) TO-DO

(5) s1 (하나 이상의 문자 포함)

(6) s1 is null

11.2. 문자열 비교 예

두 문자열 비교
#!/bin/bash
S1='string'
S2='String'
if [ $S1=$S2 ];
then
  echo "S1('$S1') is not equal to S2('$S2')"
fi
if [ $S1=$S1 ];
then
  echo "S1('$S1') is equal to S1('$S1')"
fi

나는 if $1 = $2 를 사용하는 것을 참조하기 위해 Andreas Beck이 보낸 메일을 여기서 인용했다.

이것은 $S1 또는 $S2 가 비었을 때는 그다지 좋은 생각은 아닌데 그럴 경우 parse 에러가 날 것이다. x$1=x$2 또는 "$1"="$2" 가 낫다.

11.3. 산술 연산자


+

-

*

/

% (나머지)

11.4. 산술 관계 연산자

-lt (<)

-gt (>)

-le (<=)

-ge (>=)

-eq (==)

-ne (!=)

C 프로그래머는 이 연산자를 해당하는 괄호에 있는 것에 대응시킬 수 있겠다.

11.5. 쓸만한 명령어


이 절은 Kees가 다시 썼다. 이 명령어들은 대개 완전한 프로그램 언어를 포함한다. 이 명령어들은 단지 기본만 설명한다. 좀 더 자세한 설명을 위해서는 각 명령어의 man 페이지를 보라.

sed (stream editor)

sed 는 비대화형 편집기다. 화면에서 커서를 옮겨 파일을 변경하는 대신 명령 편집 스크립트로 sed를 사용하여 편집할 파일의 이름을 추가할 수 있다. sed를 필터로 설명할 수도 있다. 몇 개의 예를 보자
  $sed 's/to_be_replaced/replaced/g' /tmp/dummy
sed는 /tmp/dummy 파일을 읽어서 'to_be_replaced'를 'replaced'로 바꾼다. 결과는 stdout(대개 콘솔)로 보내지지만 위의 줄 끝에 '> capture'를 덧붙여서 sed가 출력을 파일 capture로 보내게 할 수도 있다.

        $sed 12, 18d /tmp/dummy
sed는 12째에서 18째까지를 제외한 행을 보여준다. 원본 파일이 이 명령어에 의해 바뀌지는 않는다.

awk (데이터파일 다루기, 텍스트 추출 및 처리)

AWK의 여러가지 구현이 존재한다(가장 많이 알려진 인터프리터는 GNU의 gawk 와 'new awk' mawk.) 원칙은 간단하다. awk는 패턴을 훑고 해당되는 모든 패턴에 어떤 행동이 수행된다.

다시, 아래 행을 포함하는 파일을 만들었다.
test123 
test 
tteesstt

$ awk '/test/ {print}' /tmp/dummy

awk가 찾는 패턴은 'test'이고 /tmp/dummy 안에서 문자열 'test'를 가지고 있는 행을 찾았을 때 수행하는 것은 그 행을 출력하는 것이다.

test123 
test 

$ awk '/test/ {i=i+1} END {print i}' /tmp/dummy

3

당신이 여러 패턴을 찾을 때는, 당신은 '-f file.awk'를 가지고 따옴표사이의 텍스트를 치환해야 하며 그러면 모든 패턴과 'file.awk'의 행동을 넣을 수 있다.

grep (검색 패턴에 해당하는 행을 출력)

우리는 이전의 장에서 이미 꽤 많은 그룹 명령을 봤고, 그것은 패턴에 해당하는 행을 보여준다. 그러나 grep 은 더 많은 것을 할 수 있다.
$ grep "look for this" /var/log/messages -c

12

문자열 "look for this"는 파일 /var/log/messages에서 12번 발견되었다.


렇다 이 예는 속임수다 /var/log/messages는 꼬집어졌다 :)

wc (행, 단어, 바이트 세기)

다음의 예에서 우리는 출력이 우리가 기대하는 것이 아님을 보게 된다. 더미 파일, 이 예에서 사용된 것처럼 다음의 텍스트를 포함한다. "bash introduction howto test file"
$ wc --words --lines --bytes /tmp/dummy

2 5 34 /tmp/dummy

Wc doesn't care about the parameter order. Wc always prints them in a standard order, which is, as you can see: . 우리는 파라메터의 순서에 대해는 신경쓰지 않는다. 우리는 언제나 그것을 표준 순서로 출력한다. 그건, 당신이 보는 바와 같다.

sort (텍스트 파일의 정렬)

이번엔 더미 파일이 다음의 문자열을 포함하고 있다.
b 
c 
a

$ sort /tmp/dummy


출력은 이렇게 나온다.
a 
b 
c 


명령은 그렇게 쉽지만은 않다 :) bc (계산기 프로그램 언어)


bc는 명령행에서의 (파일로부터 입력받은, 리디렉터나 파이프가 아니라) 뿐 아니라 사용자 인터페이스에서도 계산을 수행한다. 아래의 예는 이런 명령 몇 개를 보여준다.

I start bc using the -q parameter to avoid a welcome message. 나는 환영 메시지를 피하기 위해 -q 파라메터를 썼다.
$ bc -q

1 == 5

0

0.05 == 0.05

1

5 != 5

0

2 ^ 8

256

sqrt(9)

3

while (i != 9) {

i = i + 1;

print i

}

123456789

quit

tput (터미널 또는 terminfo 데이터베이스질의 초기화)


A little demonstration of tput's capabilities: tput의 능력의 예
$ tput cup 10 4

The prompt appears at (y10,x4). 프롬프트가 (y10,x4)에 나타난다.
$ tput reset


화면을 깨끗이 하고 프롬프트가 (y1,x1)에 나타난다. (y0,x0)이 왼쪽 위 구석임을 주목하라.
$ tput cols

80

x방향에 가능한 문자수를 보여준다.

(적어도) 이들 프로그램에 익숙해지길 권한다. 명령행에서 당신이 진짜 마술을 하게 할 작은 프로그램들이 어머어마하게 많다.

몇 예제는 man 페이지나 fag에서 가져왔다.



sponsored by andamiro
sponsored by cdnetworks
sponsored by HP

Valid XHTML 1.0! Valid CSS! powered by MoniWiki
last modified 2005-07-26 11:58:59
Processing time 0.0029 sec