일할 때마다 자주 쓰기는 하는데 매번 찾아보고 작성하게 되는 shell 프로그래밍 문법에 대해서 정리해 보았습니다. IT 쪽 업무를 하시는 분들이라면 대부분의 분들이 접하는 스크립트 언어일 것 같습니다.
그런데, 다른 언어로 개발 업무를 하다 보면 자주 쓰게 되진 않아서 자꾸 문법을 잊게 만드는 언어인것 같습니다.
까먹을 때 마다 찾아보시면 좋을 것 같습니다.
그럼 역사부터 시작해 보도록 하겠습니다.
Shell Programming의 역사
shell의 역사는 아래와 같다고 합니다.
- sh : 초기의 유닉스 쉘(Bourne shell)
- ksh : 콘 쉘이라고도 불리며 1983년 데이비드 콘이 개발했으며 sh를 확장하여 만듦
- csh : 1978년 버클리 대학에서 C언어를 기반으로 만든 쉘
- bash : 1987년 브라이언 폭스에 의해 만들어진 쉘(Bourne again shell)로 sh와 대부분 호환
Shell Programming 기본 동작
편집기로 sh 파일을 만들고 실행권한을 주고 시키거나
sh 또는 bash 명령어로 실행하면 됩니다. sh는 일반적인 리눅스에서는 bash로 설정되어 있습니다.
아래와 같이 /bin/sh --version 명령어를 쳐보니, GNU bash 라고 나옵니다.
편집기로 test.sh을 생성하면 되는데, 저는 간단하게 cat 명령어를 redirection해서 test.sh 파일을 만들어 봤습니다.
vi나 다른 편집기로 만든 것과 동일합니다.
cat으로 만들 때는 작성할 내용 모두 작성 후 ctrl-d를 눌러주면 EOF(End Of File)로 종료됩니다.
아래처럼 vi로 만들어서 실행 권한을 주고 실행시켜도 됩니다.
Shell Programming 매개변수
프로그램에서도 실행할 때 인자를 주듯이 shell script도 인자를 줄 수 있습니다.
실행한 스크립트 이름이 ${0}이고 그 이후는 전달 ${1}, ${2}, ...로 전달됩니다.
위 예제처럼, shell script명 뒤에 인자를 넣을 수 있습니다.
종류 |
설명 |
$0 |
Shell
Script 명 |
$1...
$(n) |
Script에 넘겨진 n번째 아규먼트 |
$# |
argument
개수 |
$* |
Script에 전달된 인자 전체를 하나의 변수에 저장IFS(※) 변수의 첫 번째 문자로 구분 |
$@ |
Script에 전달된 인자 전체를 하나의 변수에 저장 IFS 변수를 사용하지 않고 ' '(스페이스)로 구분 |
$! |
실행을 위해
background로 보내진 마지막 실행파일 프로세스 번호 |
$$ |
Shell
script 의 PID |
$? |
가장 마지막으로 수행된 실행 결과 (백그라운드로 실행된 것 제외) |
아래와 같이 매개변수에 대한 shell을 작성후 실행시켜보면 위의 표 내용을 이해하실 수 있을 것입니다.
#!/bin/bash IFS=":" echo "script : ${0}" echo "매개변수 개수 : ${#}" echo "전체 매개변수 값 : ${*}" echo "전체 매개변수 값2 : ${@}" echo "매개변수 1 : ${1}" echo "매개변수 2 : ${2}" echo "PID : $$" var=`ps -ef|grep $$` echo ${var} }
위 Shell 코드의 결과는 아래와 같이 나온답니다. 특히 IFS를 ":"으로 지정해서 ${*}은 인자 구분 값으로 ":"를 사용한 것을 보실 수 있습니다.
그리고, PID를 출력해 보았는데 순간 두 개가 나온 것 처럼 보이지만 현재 동작하는 최초의 test.sh은 제일 처음 것입니다.
그리고, 그 안에서 `ps -ef|grep $$`를 수행했기 때문에 이 프로스세를 띄우려고 추가로 16328이 16329프로세스를 만들어서 실행한 것으로 보입니다. 또, grep의 부모 프로세스는 이 16329로 나오는 것을 보실 수 있습니다.
※ IFS
ifs는 IFS는 internal field separator의 약자다. shell이 단어를 분해할 때 사용하는 문자를 의미합니다.
default 값은 공백(space, tab, new line) 문자입니다.
Shell Programming의 명령어 대체 문법
gnu manual 페이지에 가보면 명령어 대체 문법이 아래처럼 나와 있습니다.
$(command) or `command`
#!/bin/bash var=$(echo 5) echo "var = ${var}" var=`echo "hihihi" echo "var = ${var}"
위와 같이 script를 만들고 동작시키면 아래처럼 명령어가 대체되어 var 라는 변수에 들어간 것을 보실 수 있습니다.
Shell Programming의산술 연산
기본연산 법
gnu manual 페이지에 가보면 산술연산(Arithmetic Expansion) 문법이 아래처럼 나와 있습니다.
$(( expression ))
#!/bin/bash num1=4 num2=11 echo add:$((num1+num2)) echo sub:$((num1-num2)) echo mul:$((num1*num2)) echo div:$((num1/num2)) echo mod:$((num1%num2))
산술연산은 다양한 방법이 존재하지만 제일 먼저 manual 페이지에 나온 대로 사용하는 것이 가장 쉽습니다.
expr을 이용한 산술연산
#!/bin/bash num1=10 num2=20 add=`expr \( $num1 + $num2 \)` # escape \ sub=`expr $num1 - $num2` mul=`expr $num1 \* $num2` # escape \ div=`expr $num1 / $num2` mod=`expr $num1 % $num2` echo "add: ${add}" echo "sub: ${sub}" echo "mul: ${mul}" echo "div: ${div}" echo "mod: ${mod}"
let 을 이용한 산술연산
num1=23 num2=2 let re=23+num2 #Add echo "add:$re" let re=num1-num2 #Sub echo "sub:$re" let re=num1*num2 #Mul echo "mul:$re" let re=num1/num2 #Div echo "div:$re" let re=num1%num2 #Mod echo "mod:$re"
제어문
for문
#!/bin/bash for x in 1 2 3 4 5 do echo "${x}" done data="1 2 3 4 5" for x in $data do echo ${x} done arr=(1 2 3 4 5) for i in "${arr[@]}" # arr[@] : 배열 전체 출력 do echo "${i}" done for num in `seq 1 5` do echo $num done for x in {1..5} do echo ${x} done for line in $(ls) do echo $line done
while문
#!/bin/bash count=0 while [ ${count} -le 3 ]; do echo ${count} count=$(( ${count}+1 )) done count=0 while (( ${count} <= 3 )); # 이중괄호 사용하면 논리기호 사용 가능 do echo ${count} count=$(( ${count}+1 )) done
function(함수)
#!/bin/bash function testf() { param1=$1 param2=$2 param3=$3 echo $param1 # a echo $param2 # b echo $param3 # $1 echo $@ # 파라미터 전체 출력 } testf "a" "b" $1
프로그램 반환 값 (종료 상태 코드)
프로그램 반환 값
리눅스 종료 상태 코드
아래는 종료 상태 코드에 대한 표준 규칙입니다. 0 : 명령이 성공적으로 완료됨 1 : 알 수 없는 오류 2 : 쉘 명령을 잘못 사용함 126 : 명령을 실행할 수 없음. (Permission denied) 127 : 명령을 찾을 수 없음. (command not found) 128 : 잘못된 종료 매개변수. 128+x : 치명적인 오류 130 : <Ctrl>+<C>로 명령이 종료됨. 255 : 종료 상태가 범위를 벗어남. (종료 상태가 255 초과)
실습예제
#!/bin/bash count=0 while [ ${count} -le 3 ]; do echo ${count} count=$(( ${count}+1 )) done count=0 while (( ${count} ${logfile}.txt filenumber=`expr ${filenumber} + 1` logfile="${logfilehdr}${filenumber}" done echo "${logfile} end"
위와 같이 shell script를 만들고, 아래처럼 수행하면 146개의 파일이 한 번에 dump 되어 출력됩니다.
파일을 자세히 보면 아래와 같이 특정 로그파일에 대한 text 파일로 dump되어있는 것을 보실 수 있습니다.
오늘은 업무에 활용할 수 있는 shell script를 작성하고 사용해 보았습니다.
생각 안 날 때 한 번씩 들려서 찾아보시면 좋을 것 같습니다.
참고자료:
https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html