Basic bash

From Biocourse.org

Jump to: navigation, search
BioInfoSystem | Bash

#
- 주석, 이스케이프된( " ' \ ) #은 주석이 아님.

;
- 둘 이상의 명령어 한줄에 사용가능

;;
- case 옵션 종료자
    case "$variable" in
    abc)  echo "$variable = abc" ;;
    xyz)  echo "$variable = xyz" ;;
    esac

exit
-  스크립트의 마지막에 실행, script 의 끝을 나타냄. 성공시 0 값을 리턴 (exit 0~255)
-  조건 부정시 ! 사용: (예, ! + 공백 + true)

.
-  [마침표] source 명령어와 동일. bash 내장 명령(builtin)
- 정규 표현식(reqular expression): 한 개의 문자
숨김 파일

"
partial quoting, 이중 쿼우트 내의 문자열에 들어 있는 거의 대부분의 특수 문자를 거의 해석 못하도록함


'
full quoting, 단일 쿼우트 내의 모든 특수 문자를 해석하지 못하도록 "보다 더 강한 형태의 쿼우팅

,
 
콤마 연산자 는 연속적인 산술 연산시 사용. 모든 계산이 이루어진뒤, 마지막에 계산된 결과만 리턴됩니다.

let "t2 = ((a = 9, 15 / 3))"  # "a"를 세트하고 "t2"를 계산.


\
 
\X라고 하면 X 문자를 "이스케이프" 시키고, 'X' 라고 "쿼우팅" 시키는 것과 동일한 효과. \"'이 문자 그대로 해석되도록 쿼우트 할 때 쓰일 수도 있습니다.
/ 
파일명 경로 구분자. [슬래쉬] 파일명에 등장하는 각 요소들을 구분해 줍니다(예,/home/bozo/projects/Makefile).
또는 나누기 산술 연산자

`
 
명령어 치환(command substitution). [백틱(backticks)] `명령어` 라고 하면 명령어의 결과를 변수값으로 설정할 수가 있습니다. 다른 말로 backticks나 역쿼우트(backquote)라고도 합니다.

* 
와일드 카드. [별표] * 문자는 정규 표현식에서 0개 이상의 문자를 나타내는 것과 동일하게 파일명 확장(globbing)에서 "와일드 카드"처럼 쓰입니다.

이중 별표, **, 는 수학의 누승(累乘, exponentiation) 연산자입니다.

?

와일드 카드(하나의 문자). [물음표] ? 문자는 확장 정규 표현식에서 한 문자를 나타내는 것과 마찬가지로 글로빙(globbing)에서 파일명 확장을 나타내는 한 문자짜리 "와일드 카드"의 역할을 합니다.

?이중 소괄호에서 C 스타일의 삼중 연산자로도 쓰입니다. 예 9-22를 참고하세요.

$

변수 치환.

var1=5
var2=23skidoo

echo $var1 # 5 echo $var2 # 23skidoo

$정규 표현식에서 줄의 끝을 나타냅니다.

${}

$*, $@

()

명령어 그룹.

(a=hello; echo $a)

중요: 소괄호로 묶인 명령어들은 서브쉘에서 동작합니다.

스크립트의 다른 곳에서는 소괄호 안의 서브쉘에 들어 있는 변수들을 볼 수가 없습니다. 부모 프로세스인 스크립트는 자식 프로세스(서브쉘)에서 만들어진 변수를 읽을 수가 없습니다.

a=123
( a=321; )		  

echo "a = $a" # a = 123

  1. 소괄호 안의 "a" 는 지역변수처럼 동작합니다.

배열 초기화.

Array=(element1 element2 element3)

{xxx,yyy,zzz,...}

중괄호 확장.

grep Linux file*.{txt,htm*}

  1. "fileA.txt", "file2.txt", "fileR.html", "file-87.htm" 등등의 파일에서
  2. "Linux"가 들어 있는 것을 모두 찾음

명령어는 중괄호안의 콤마로 분리 지정된 파일 스펙에 맞게 동작할 것입니다. [1] 파일명 확장(globbing)은 중괄호 안에서 지정된 파일 스펙에 적용됩니다.

 

경고

빈 칸은 쿼우트(quote)나 이스케이프(escape)되지 않고 중괄호에서 쓰일 수 없습니다.

echo {file1,file2}\ :{\ A," B",' C'}

file1 : A file1 : B file1 : C file2 : A file2 : B file2 : C

{}

코드 블럭. [중괄호] "인라인 그룹"이라고도 부르는 중괄호 한 쌍은 실제로 익명의 함수를 만들어 냅니다만 보통의 함수와는 달리 코드 블럭 안의 변수들을 스크립트의 다른 곳에서 볼 수가 있습니다.

bash$ { local a; a=123; }
bash: local: can only be used in a function
		  

a=123
{ a=321; }
echo "a = $a"   # a = 321   (코드 블럭에서 설정된 값)

  1. Thanks, S.C.

중괄호로 묶인 코드 블럭은 I/O 재지향되거나 재지향을 받을 수 있습니다.

예 4-1. 코드 블럭과 I/O 재지향

#!/bin/bash

  1. /etc/fstab 읽기

File=/etc/fstab

{ read line1 read line2 } < $File

echo "$File 파일의 첫번째 줄:" echo "$line1" echo echo "$File 파일의 두번째 줄:" echo "$line2"

exit 0

예 4-2. 코드 블럭의 결과를 파일로 저장하기

#!/bin/bash

  1. rpm-check.sh
  1. rpm 파일에 대해서 설치가능여부, 설치정보, 설치목록에 대해서 쿼리를 하고,
  2. + 그 결과를 파일로 저장합니다.
  3. 이 스크립트는 코드 블럭이 어떻게 쓰이는지 보여줍니다.

SUCCESS=0 E_NOARGS=65

if [ -z "$1" ] then

 echo "사용법: `basename $0` rpm-file"
 exit $E_NOARGS

fi

{

 echo
 echo "아카이브 정보:"
 rpm -qpi $1	   # 설치정보 쿼리.
 echo
 echo "아카이브 목록:"
 rpm -qpl $1	   # 설치목록 쿼리.
 echo
 rpm -i --test $1  # 설치가능여부 쿼리.
 if [ "$?" -eq $SUCCESS ]
 then

echo "$1 는 설치될 수 있습니다."

 else

echo "$1 는 설치될 수 없습니다."

 fi  
 echo

} > "$1.test" # 블럭의 모든 출력을 파일로 재지향.

echo "$1.test 파일에 rpm 테스트의 결과가 저장되었습니다."

  1. 여기서 쓰인 옵션에 대한 설명은 맨 페이지를 참고하세요.

exit 0

참고: 위에서 설명했던 (소괄호)로 묶인 명령어 그룹과는 달리 {중괄호}로 묶인 코드 블럭은 보통은 서브쉘을 띄우지 않습니다.. [2]

{} \;

경로명. 주로 find에서 쓰이고, 쉘 내장 명령아닙니다.

참고: ";"find 명령어의 -exec 옵션이 여러개 나올 때 끝을 나타내기 때문에 쉘이 해석하는 것을 막기 위해서 이스케이프 시켜줘야 됩니다.

[ ]

테스트.

[ ] 사이의 테스트문. [는 쉘 내장 명령인 test와 동의어로서, 외부 명령어인 /usr/bin/test의 링크가 아닙니다.

[[ ]]

테스트.

[[ ]] 사이의 테스트문(쉘 키워드).

더 자세한 사항은 ... 을 참고하세요.

(( ))

정수 확장.

(( ))에 들어 있는 정수 표현식을 확장하고 평가해 줍니다.

더 자세한 설명은 (( ... ))를 참고하세요.

> >& >> <

scriptname >filenamescriptname의 결과를 filename으로 재지향시킵니다. 이 때, fielname이 이미 있다면 덮어 써집니다.

command >&2command의 결과를 표준에러로 재지향 시킵니다.

scriptname >>filenamescriptname의 결과를 filename 으로 덧붙입니다. 이 때, filename이 없다면 새로 만듭니다.

프로세스 치환(process substitution).

(command)>

<(command)

"<"">" 문자는 다른 문맥에서 문자열 비교 연산자로 동작합니다.

또 다른 문맥에서는 정수 비교 연산자로 동작합니다. 예 12-6를 참고하세요.

<<

here document에서 쓰이는 재지향.

|

파이프. 여러 명령어들을 연결하는 방법으로써, 한 명령어의 출력을 다음 명령어나 쉘에게 전달.

echo ls -l | sh

  1. "echo ls -l" 의 출력을 쉘에게 전달하는데,
  2. + 그냥 "ls -l" 라고 한 것과 똑같습니다.


cat *.lst | sort | uniq

  1. 모든 ".lst" 파일들을 합친 다음 정렬하고 중복된 줄들을 지웁니다.

명령어의 출력이나 명령어 자체를 스크립트로 파이프를 걸 수도 있습니다.

#!/bin/bash

  1. uppercase.sh : 입력을 대문자로 바꿔줌.

tr 'a-z' 'A-Z'

  1. 한 글자짜리 파일 이름이 생기는 걸 막기 위해서
  2. + 문자 범위는 꼭 쿼우트 시켜야 합니다.

exit 0

자, 이제 ls -l의 출력에 파이프를 걸어 이 스크립트로 넘겨 봅시다.

bash$ ls -l | ./uppercase.sh
-RW-RW-R--	1 BOZO  BOZO	   109 APR  7 19:49 1.TXT

-RW-RW-R--	1 BOZO  BOZO	   109 APR 14 16:48 2.TXT
-RW-R--R--	1 BOZO  BOZO	   725 APR 20 20:56 DATA-FILE

참고: 파이프로 묶인 각 프로세스의 표준출력은 다음 명령어의 표준입력으로 읽혀야 합니다. 이런식으로 동작하지 않는다면 데이타의 흐름은 블럭될 것이고 파이프는 생각했던대로 동작하지 않을 것입니다.

cat file1 file2 | ls -l | sort

  1. "cat file1 file2" 의 출력은 나타나지 않습니다.

파이프는 자식 프로세스로 돌기 때문에 스크립트의 변수값을 바꿀 수가 없습니다.

variable="initial_value"
echo "new_value" | read variable
echo "variable = $variable"	 # variable = initial_value

파이프로 연결된 명령어중 하나가 취소된다면 전체 실행이 취소되는데 이를 broken pipe라고 하고, 이 때 SIGPIPE 시그널이 발생 됩니다.

>|

강제 재지향(noclobber 옵션이 켜 있더라도). 파일이 이미 존재하더라도 강제로 덮어 쓰게 합니다.

&

작업을 백그라운드로 돌리기. 명령어 뒤에 &를 붙여 주면 백그라운드로 실행됩니다.

bash$ sleep 10 &
[1] 850
[1]+  Done					sleep 10
		  

 

경고

스크립트에서 어떤 명령어를 백그라운드로 돌리게 되면 키가 눌리길 기다리면서 스크립트가 멈춰버립니다. 다행스럽게도 이런 상황을 피해 갈 수 있는 방법이 있습니다.

-

표준입력(stdin)과 표준출력(stdout) 서로간의 재지향. [대쉬]

(cd /source/directory && tar cf

- . ) | (cd /dest/directory && tar xpvf -)
  1. 한 디렉토리의 전체 파일 구조를 다른 디렉토리로 옮김
  2. [Alan Cox <a.cox@swansea.ac.uk> 제공, 약간의 수정]
  3. 1) cd /source/directory 옮겨질 파일들이 있는 소스 디렉토리
  4. 2) && "And-list": 'cd' 명령이 성공하면 다음 명령어가 실행됨
  5. 3) tar cf - . 'c' 옵션은 새 아카이브를 만들라는 명령어
  6. 'f'(file) 옵션은 그 뒤에 나오는 '-'에 의해 타켓 파일을 표준 출력으로 지정해 주고,
  7. 현재 디렉토리 트리(.)를 대상으로 하게 합니다.
  8. 4) | 파이프를 걸고
  9. 5) ( ... ) 서브쉘
  10. 6) cd /dest/directory 옮길 디렉토리로 이동
  11. 7) && 위에서 설명했던 "And-list"
  12. 8) tar xpvf - 아카이브를 풀고('x'), 소유권과 파일 퍼미션을 유지('

p')하고

  1. 표준출력으로 메세지를 많이(verbose) 찍게 하고('v')
  2. 표준입력에서 데이터를 읽어 들임('f' 다음의 '-')
  3. 'x'는 명령어고, 'p', 'v', 'f'는 옵션입니다. 주의하세요.
  4. 헥헥~~~~


  1. 똑같지만 더 우아한 방법:
  2. cd source-directory
  3. tar cf - . | (cd ../target-directory; tar xzf -)
  4. cp -a /source/directory /dest 도 같은 결과가 나옵니다.

bunzip2 linux-2.4.3.tar.bz2 | tar xvf -

  1. --tar 파일을 풀어서 -- | --"tar" 에게 넘김 --
  2. "tar"에 "bunzip2"를 처리하는 패치가 안 돼 있다면
  3. 파이프를 써서 두 단계로 나누어 처리를 해 줘야 합니다.
  4. 여기서는 "bzip"으로 압축된 커널 소스를 푸는 것을 보여줍니다.

여기서 쓰인 "-"는 Bash 연산자가 아니고, tarcat 같은 몇몇 유닉스 유틸리티들이 인식해서 표준출력으로 쓰도록 해주는 옵션임에 주의하세요.

파일명이 나와야 할 곳에 -이 나오면 표준출력으로 결과를 재지향하든지(tar cf에서 가끔 쓰죠), 실제 파일에서 입력을 받지 않고 표준입력에서 받도록 재지향 하게 해 줍니다. 주로 파일을 다루는 유틸리티들을 파이프에서 필터로 쓸 때 이 방법을 씁니다.

bash$ file
사용법: file [-bciknvzL] [-f namefile] [-m magicfiles] file...
		  

file이 명령어줄에서 옵션없이 불리면 에러 메세지를 내면서 실패합니다.

bash$ file -
#!/bin/bash
standard input:			  Bourne-Again shell script text executable
		  

이번에는 자신의 입력을 표준입력에서 받고 그 결과를 필터링 합니다.

- 는 표준출력을 다른 명령어로 파이프 시키는데 쓰일 수 있습니다. 이렇게 하면 파일의 앞쪽에 줄을 삽입하기같은 묘기도 부릴 수 있습니다.

diff를 써서 섹션을 가진 두 파일을 비교해 보기 바랍니다.

grep bash file1 | diff file2 -

마지막으로, tar-를 쓴 현실적인 예제입니다.

예 4-3. 최근 하루동안 변경된 파일들을 백업하기

#!/bin/bash

  1. 현재 디렉토리의 모든 파일중 최근 24시간 안에 변경된 파일들을
  2. + 타르로 묶고 gzip으로 압축한 "타르볼"로 백업

NOARGS=0 E_BADARGS=65

if [ $# = $NOARGS ] then

 echo "사용법: `basename $0` filename"
 exit $E_BADARGS

fi

tar cvf - `find . -mtime -1 -type f -print` > $1.tar gzip $1.tar


  1. 너무 많은 파일이 발견되거나 파일명에 빈 칸이 들어있다면 위의 코드는
  2. + 실패할 수도 있다고 Stephane Chazelas 가 지적해 주었습니다.
  1. 그가 제안한 다른 방법은 다음과 같습니다:
  2. -------------------------------------------------------------
  3. find . -mtime -1 -type f -print0 | xargs -0 tar rvf "$1.tar"
  4. "find"의 GNU 버전을 쓴 방법.
  1. find . -mtime -1 -type f -exec tar rvf "$1.tar" '{}' \;
  2. 다른 유닉스에서도 쓸 수 있지만 더 느린 방법.


exit 0

 

경고

파일명이 -로 시작하는 파일이 - 재지향 연산자와 같이 쓰이면 문제가 생길 수도 있습니다. 스크립트 내에서 이런 사항을 확인한 다음에 ./-FILENAME이나 $PWD/-FILENAME등으로 바꿔서 처리해 줘야 합니다.

또한, 변수의 값이 -로 시작할 경우에도 비슷한 문제가 생길 수 있습니다.

var="-n"
echo $var

  1. "echo -n" 처럼 해석이 되어 결과가 안 나타납니다.

-

바로 전 작업 디렉토리. [대쉬] cd - 라고 하면 $OLDPWD 환경 변수를 이용해서 바로 전 작업 디렉토리로 옮겨갑니다.

 

경고

방금 위에서 설명한 재지향 연산자인 "-"와 헷갈리면 안 됩니다. "-"는 문맥에 따라 알맞게 해석됩니다.

-

빼기. 산술 연산에서 쓰이는 빼기 부호.

=

Equals. 할당 연산자

a=28
echo $a   # 28

"="다른 문맥에서 쓰이면 문자열 비교 연산자입니다.

+

더하기. 덧셈 산술 연산자.

+다른 문맥에서 쓰이면 정규 표현식 연산자입니다.

%

나머지(modulo). 나눗셈의 나머지 산술 연산자.

%다른 문맥에서 쓰이면 패턴 매칭 연산자입니다.

~

홈 디렉토리. [틸드] 이 문자는 $HOME 내부 변수에 해당합니다. ~bozo 는 bozo의 홈 디렉토리를 나타내고 ls ~bozo 는 그 홈 디렉토리의 내용을 보여줍니다. ~/ 은 현재 사용자의 홈 디렉토리를 나타내고, ls ~/ 는 그 홈 디렉토리의 내용을 보여줍니다.

bash$ echo ~bozo
/home/bozo

bash$ echo ~ /home/bozo

bash$ echo ~/ /home/bozo/

bash$ echo ~: /home/bozo:

bash$ echo ~nonexistent-user ~nonexistent-user

~+

현재 작업 디렉토리. 이 문자는 $PWD 내부 변수에 해당합니다.

~-

바로 전 작업 디렉토리. 이 문자는 $OLDPWD 내부 변수에 해당합니다.

제어 문자

터미널이나 텍스트 디스플레이의 동작을 변경. 제어 문자는 CONTROL + key 조합으로 나타낼 수 있습니다.

 

  • Ctl-C

    포그라운드 작업을 끝냄.

  • Ctl-D

    쉘에서 로그 아웃(exit와 비슷함).

    "EOF" (파일끝, end of file). 표준입력에서 들어오는 입력을 끝냄.

  • Ctl-G

    "벨(BEL)"(삑 소리).

  • Ctl-H

    백스페이스(backspace).

  • Ctl-J

    캐리지 리턴(carriage return).

  • Ctl-L

    폼피드(formfeed, 터미널 화면을 청소). clear 명령어와 똑같은 효과.

  • Ctl-M

    뉴라인(Newline).

  • Ctl-U

    입력줄을 지움.

  • Ctl-Z

    포그라운드 작업을 잠시 멈춤.

공백문자(whitespace)

명령어나 변수의 구분자 역할. 공백문자는 빈칸, 탭, 빈줄들의 어떠한 조합들로 이루어져 있습니다. 변수 할당같은 상황에서 공백문자를 쓰면 문법 에러가 납니다.

빈줄은 스크립트 동작에 아무 영향도 주지 않기 때문에 기능별로 구분시켜서 보기 좋게 하는데 쓸 수 있습니다.

특수 변수인 $IFS는 어떤 명령어의 입력 필드를 구분해 주는데 이 변수의 디폴트값은 공백문자입니다.

:

널 명령어(null command). 쉘의 "NOP"(no op, 아무 동작도 않함)에 해당합니다. 쉘 내장 명령인 true의 동의어라고도 볼 수 있습니다. 주의할 점은 :은 bash 내장 명령이기 때문에 종료 상태0이라는 것입니다.

:
echo $?   # 0

무한 루프:

while :
do

  첫번째 연산 
  두번째 연산
  ...
  n번째 연산

done

  1. 이는 다음과 같습니다:
  2. while true
  3. do
  4. ...
  5. done

if/then 테스트 문의 Placeholder:

if condition
then :   # 아무것도 안 하고 계속 진행
else

  어떤 작업

fi

이진 연산의 placeholder 제공, 예 8-1디폴트 매개변수 참고.

: ${username=`whoami`}

  1. "username"이 명령어나 내장 명령어가 아닌 경우에
  2. ${username=`whoami`} 에 : 없이 쓰면 에러가 납니다.

here document가 나올 곳의 placeholder를 제공. 예 17-8 참고.

매개변수 치환을 써서 변수의 문자열 평가(예 9-10 참고).

: ${HOSTNAME?} ${USER?} ${MAIL?}

  1. 필수적인 환경변수중 하나라도 세트가 안 돼 있다면 에러를 출력.

변수 확장/문자열 조각 대치(Variable expansion / substring replacement).

재지향 연산자>과 같이 써서 특정 파일의 퍼미션 변경 없이 크기를 0으로 만들어 줍니다. 파일이 없었다면 새로 만들어 냅니다.

: > data.xxx   # "data.xxx"은 이제 빈 파일입니다.		  

  1. cat /dev/null >data.xxx 라고 한 것과 동일하지만
  2. ":"가 내장 명령어이기 때문에 새 프로세스를 포크(fork) 시키지 않습니다.

예 12-11 참고.

역시 재지향 연산자인 >>과 같이 쓰면 파일의 억세스/변경 시간을 업데이트 해 줍니다(: >> new_file). 파일이 없었다면 새로 만들어 냅니다. touch와 같습니다.

참고: 보통 파일에만 사용하고 파이프나 심볼릭 링크, 특수 파일에는 사용하지 마세요.

권장하는 방법은 아닙니다만, 주석의 시작을 나타낼 때 쓸 수도 있습니다. 주석에 #을 쓰게 되면 그 줄의 나머지 부분에 대해서 에러 확인을 안 하기 때문에 어떤 문장도 올 수 있지만 :의 경우는 다릅니다.

: 이 주석은 에러를 발생시킵니다, ( if [ $x -eq 3] ).

":"는 또한 /etc/passwd$PATH 변수에서 필드 구분자로도 쓰입니다.

bash$ echo $PATH
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/sbin:/usr/sbin:/usr/games

!

테스트나 종료 상태의 의미를 반대나 부정해 줍니다. ! 연산자는 해당 명령어의 종료 상태를 반대로 해 놓습니다(예 3-2 참고). 또한, 테스트 연산자의 의미도 거꾸로 바꿔 주는데 예를 들어, "equal"( = )을 "not-equal" ( != )로 해석하게 해 줍니다. ! 연산자는 bash 키워드입니다.

다른 상황에서는 간접 변수 참조의 의미로도 쓰입니다.

Personal tools
Google AdSense