4,497,087 th visitor since 2017.2.1 ( Today : 866 )
Computer ???
No. 249
Name. swindler
Subject. bash howto #1
Main Cate. Linux
Sub Cate.
Date. 2007-06-19 14:53
Hit. 4863 (211.181.247.3)
File.
2. 아주 간단한 스크립트!!
이 하우투는 예제를 바탕으로 셸 스크립트 프로그래밍의 방법을 제시할 것이다.

먼저 이해하기 쉬운 간단한 스크립트를 사용하여 기본 문법을 알아보자.

2.1. hello world를 출력하는 스크립트

#!/bin/bash
echo Hello World



이 스크립트는 단지 두 줄로 되어 있을 뿐이지만, 스크립트로서 갖추어야 할 기본적인 요소는 갖추고 있다. 먼저 첫 번째 줄에서는 이 파일을 실행하기 위해 필요한 프로그램의 경로를 명기했다. 아마도 다들 알고 있겠지만, bash란 셸의 일종이며, /bin/bash는 이 셸의 실행 파일이 있는 경로이다. 셸은 명령어 해석기로 들어오는 명령을 해석하여 이것이 내부 명령어라면 바로 실행을, 외부 명령어라면 해당하는 실행 파일을 찾아 메모리에 필요한 부분을 적재한다. 이 부분이 없다면 다음에 오는 명령을 실행할 수는 없을 것이다.

두 번째 줄은 실제적인 명령을 내리는 부분이다. 여기에서는 'Hello World'라는 말을 터미널에 출력하라는 명령을 내렸다. 물론 다른 말로 바꾸어도 좋을 것이다.

여담! 우리의 리누스 토발즈 아저씨가 처음 만들었던 것도 화면에 문장을 출력하는 프로그램이었다. 아마 그 프로그램의 업버전은 'sarah is the best'라는 문장이었다나 뭐라나..... (사라는 리누스 아저씨의 동생 이름이다.)

만약에 ./hello.sh: Command not found. 와 같은 꼴을 보게 되었다면, 아마도 첫 번째 줄의 '#!/bin/bash'가 문제일 것이다. 'whereis bash'나 'finding bash' 명령을 내려 bash의 경로를 확인해 보자. 그리고 이 경로를 첫 번째 줄에 기입한다.

2.2. 엄청나게 간단한 백업 스크립트

#!/bin/bash
tar -cZf /var/my-backup.tgz /home/me/



이 스크립트는 터미널에 메시지를 출력하는 대신 사용자의 홈 디렉토리를 tar-ball형식으로 묶는다. 이 스크립트는 실제로 사용할 만한 것은 아니다. 먼저 사용자에 따라 경로를 일일히 조절해야 하며, 여러 사람이 사용하면 백업 파일이 서로 덮어 쓰게 되어 백업이 망가질 수도 있다. 이런 백업 스크립트를 실제로 사용할 만 하게 만들어 놓은 것이 뒷 부분에 나올 것이다. 이것은 그냥 예제일 뿐이니까, 한번 시험해 보고는 바로 삭제하는 것이 좋을 것이다.

3. 리디렉션의 모든 것
3.1. 정의와 기본 설명
stdin(표준 입력), stdout(표준 출력), stderr(표준 에러)라는 세 가지의 파일 디스크립터가 있다. 파일 디스크립터가 무엇인지 일일히 설명하기는 그렇고.... 간단하게 이해해 보자. 어떤 프로그램을 실행했을 때 화면에 주루룩 하고 원하는 결과가 뜨는 것이 표준 출력이다. 어떤 프로그램을 실행하기 위해 꼭 필요한 요소를 프로그램을 실행할 때 같이 입력해 주는 것이 표준 입력이다. 이 정도만 알고 시작하면 될 것이다.

먼저 다음과 같은 내용을 간단히 실행해 보자. 백문이 불여일견, 백견이 불여일행인 법. ^^


표준 출력을 파일로 보내기

표준 에러를 파일로 보내기

표준 출력을 표준 에러로 보내기

표준 에러를 표준 출력으로 보내기

표준 에러와 표준 출력을 파일로 보내기

표준 에러와 표준 출력을 표준 출력으로 보내기

표준 에러와 표준 출력을 표준 에러로 보내기

먼저 간단히 말해두겠는데, 버퍼에 남아 있는 표준 출력이나 표준 에러를 화면에 출력해 보는 것은 아주 쉽지만, 그 시도와 동시에 내용이 날아간다는 점을 상기하자.

3.2. 예제 : 표준 출력을 파일로 보내기
프로그램의 실행 결과를 파일에 바로 저장하는 방법이다. 이 방법은 언제 쓰면 좋으냐 하면.... 그렇다, 수치해석 숙제 할 때 줄줄이 에러값 나오는 것, 이 방법으로 하면 파일에 기록하는 코드 없이도, 화면 캡처 따위 하지 않아도 아주 간단하게 해결된다. ^^


ls -l > ls-l.txt



이 내용을 실행하고 나면, 화면에 'ls -l' 명령의 실행 결과가 출력되는 대신 'ls-l.txt'라는 이름의 파일이 생긴다. 이 파일을 열어 보면 원래 'ls -l' 을 실행했을 때의 결과가 그대로 저장되어 있다. 이런 이름의 파일이 원래 있었다면, 파일의 앞부분에 그대로 출력 내용이 덮어 씌워져 버리니 주의하자.

3.3. 예제 : 표준 에러를 파일로 보내기
방법은 마찬가지이다. 이 경우에는 에러 메시지를 파일에 저장하는 것 뿐이다. 역시 같은 방법으로 다음과 같이 해 보자.


grep da * 2> grep-errors.txt



앞서 표준 출력을 파일로 보냈을 때와 마찬가지로, 'grep-errors.txt' 파일이 만들어지며 화면 대신 이 파일 안에 에러 메시지가 기록된다. 여기에서 숫자 2는 표준 에러를 뜻하는 파일 디스크립터이다. 2가 들어가지 않으면 표준 출력이 저장된다.

3.4. 예제 : 표준 출력을 표준 에러로 보내기
이 방법은 프로그램을 실행했을 때의 표준 출력을 표준 출력 디스크립터 대신 표준 에러와 같은 방식으로 출력하는 것이다.


grep da * 1>&2



이와 같은 방법으로 명령의 표준 출력이 표준 에러에게 넘겨졌다. 그런데 정말 이것만으로 이해가 착착 간다면 정말 이 문서 볼 필요 없다. 어쩔 수 없이 추가 설명을 달아야만 하는 부분인데..... 간단히 설명하겠다. 'grep da *'는 우리가 익히 알고 있는 단순한 명령이다. 이 뒤에 붙은 숫자는 파일 디스크립터이며 특히 1은 표준 출력을 의미한다. 2는 표준 에러 되겠다. 그런데 사실, 조금만 신경 쓰면 알 수 있는 부분이지만 '1>'는 그냥 '>'와 같은 것이다. 이유는 각자 생각해 보자. 금방 결론이 나올 것이다. 참고로 0은 표준 입력, 3 이후는 다른 파일이 입출력용으로 할당될 때 사용하는 것으로, 그냥 적어 넣으면 에러 메시지를 볼 수 있을 것이다.

리디렉션을 '2>&1'과 같이 주면 표준 에러를 표준 출력과 같은 곳으로 보내라는 뜻이며, '1>&2'의 경우는 표준 출력을 표준 에러와 같은 곳으로 보내라는 뜻이다.

3.5. 예제 : 표준 에러를 표준 출력으로 보내기
위 내용을 잘 섭렵해 왔다면 생각해 볼 필요도 없는 부분이다.


grep * 2>&1



자, 표준 에러를 표준 출력으로 보내어 함께 출력하였다. 만약에 이 결과를 파이프를 통해 more나 less 등으로 보낸다면, 표준 출력과 표준 에러가 뒤섞인 형태를 보게 될 것이다.

3.6. 예제 : 표준 출력과 표준 에러를 파일로 보내기
이 내용 역시 위와 똑.같.다. 라고 봐도 무방하지만..... 이것을 한번에 파일로 보내는 부분은 함께 보도록 하자.


rm -f $(find / -name core) &> /dev/null



따로이 디스크립터를 사용할 필요 없이 '&>'로 리디렉션 하는 것 만으로 해결된다. 이 방식은 표준 출력과 표준 에러를 함께 파일로 보낼때 사용한다. 이 명령을 크론에 넣어 두면, 일정한 시간마다 모든 디렉토리에 있는 core 파일을 삭제한다. 여기에서는 표준 출력과 표준 에러를 모두 '/dev/null'로 보내 실제로는 날려 버리지만, 굳이 이 내용을 확인하고 싶다면 적당한 파일로 출력하여 살펴보도록 하자.

4. 파이프(pipes)
이 장에서는 파이프를 사용하는 간단하면서도 실질적인 예를 들어 보겠다.

4.1. 파이프로 무엇을 할 수 있을까
파이프는 정말 간단한 방법으로, 한 프로그램에서의 출력을 다른 프로그램의 입력으로 보낸다. 이렇게 "흘려 보내기"때문에 파이프다.... 라고 생각하면 딱 맞을 것이다. ^^

4.2. 예제 : sed를 이용한 아주 간단한 파이프 예제
다음은 파이프를 이용하는 가장 간단한 실례이다.


ls -l | sed -e "s/[aeio]/u/g"


그러면 한번 위 내용을 찬찬히 살펴보자. 먼저 'ls -l' 명령이 실행되었다. 그리고 이 결과는 화면에 출력되는 대신, 파이프를 타고 sed 프로그램에 전달되어 다시 한번 처리된 후 화면에 출력된다.

4.3. 예제 : 'ls -l *.txt'의 색다른 형태
아마도 이 방법은 'ls -l *.txt'를 사용하는 것 보다는 까다로운 것이겠지만, 파이프의 사용에 대해서만큼은 확실히 보여줄 수 있다.


ls -l | grep "\.txt$"


여기서 'ls -l'의 결과는 grep으로 넘어가, "\.txt$"라는 조건에 맞는 값만을 화면에 출력한다. 이 결과는 'ls -l *.txt'와 같다.

5. 변수
다른 프로그래밍 언어를 사용할 때와 마찬가지로, 셸 프로그래밍을 할 때도 변수를 사용할 수 있다. 게다가 bash에서는 데이터 타입을 미리 정할 필요 없이, 숫자나 문자, 혹은 문자열을 지정할 수 있다.

어떤 변수가 처음 사용되는 순간 참조가 생성되므로, 변수를 따로 선언할 필요는 없다.

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

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



2번째 줄에서 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는 원하는 대로 옵션을 조절하여 다른 포맷으로 출력할 수도 있으니 확인해 보자. 또한 이 스크립트를 실행하면 명령 실행 과정이 화면에 그대로 출력된다는 점도 참고해 두자.

참고할 만한 것을 좀 보자. 다음 내용을 각각 직접 실행해 보자.


echo ls
echo $(ls)



무엇이 다른지 확인하고, 왜 다른지도 알아보자.

5.3. 지역 변수
지역 변수는 local이라는 키워드를 사용하여 생성된다.


#!/bin/bash
HELLO=Hello
function hello {
local HELLO=World
echo $HELLO
}
echo $HELLO
hello
echo $HELLO



이 예제는 지역 변수를 사용하는 방법에 대한 것이다. 이미 프로그래밍 언어를 조금이라도 다루어 보았다면 이런 방식의 코드를 본 적이 있을 것이다. 여기에서는 함수를 호출하는 방법에도 주의하자.



[바로가기 링크] : http://coolx.net/cboard/computer/249



Name
Password
Comment
Copyright © 1999-2017, swindler. All rights reserved. 367,611 visitor ( 1999.1.8-2004.5.26 ), 2,405,771 ( -2017.01.31)

  2HLAB   2HLAB_Blog   RedToolBox   Omil   Omil_Blog