쉘 스크립트 프로그래밍

Park, Jinyong·2020년 4월 18일
4

Shell script programming

목록 보기
1/5

이것이 우분투 리눅스다 의 쉘 스크립트 프로그래밍 챕터를 정리한 내용입니다.

Shell

쉘은 사용자가 입력한 명령을 해석해 커널에 전달하거나, 커널의 처리 결과를 사용자에게 전달하는 역할을 한다.

쉘의 명령문 처리 방법

쉘 명령문은 명령문과 함께 여러 옵션과 인자를 함께 사용할 수 있다.

(프롬프트) 명령 [옵션...] [인자...]

> ls -l
> rm -rf /myDir

>가 프롬프트, rm이 명령, -rf가 옵션, /myDir가 인자가 된다.

쉘의 환경변수

쉘은 여러 환경 변수 값을 가지고 있고, echo $환경변수이름 명령을 통해 설정된 환경 변수 값을 확인할 수 있다. export 환경변수=값 명령을 통해 환경 변수를 변경하거나 추가할 수 있다. printenv 명령으로 환경 변수와 값을 확인할 수 있지만, 일부 환경 변수는 나타나지 않을 수 있다.

> echo $LANG
ko_KR.UTF-8
> export $LANG=en_US.UTF-8

> printenv

쉘 스크립트 프로그래밍

리눅스의 대부분은 C로 작성되었으므로, 쉘 스크립트는 C언어와 유사한 방법으로 프로그래밍할 수 있다. C언어와 달리, 쉘 스크립트는 컴파일하지 않고도 쉘에서 바로 실행할 수 있다.

#!/bin/sh

#! 명령어로 내가 사용하려는 명령어 해석기가 무엇인지 알려줘야 하므로, 첫 행에 꼭 써야 한다. 우분투에서 /bin/shdash를 가리키고 있는데 기능이 한정되어 있으므로 제대로 기능이 풍부한bash를 사용하려면 #!/bin/bash로 수정하면 된다.

*.sh 파일

쉘 스크립트 파일의 확장자는 .sh이다. .sh 파일을 생성하면 아직 '실행 가능'한 상태가 아니다. '실행 가능' 속성을 추가해야 한다.

> ls -l *.sh
-rw-rw-r--  1  jinyongp  jinyongp   111 B    Sat Apr 18 14:09:52 2020  test.sh

> chmod +x test.sh
-rwxrwxr-x  1  jinyongp  jinyongp   111 B    Sat Apr 18 14:06:44 2020  test.sh

sh 명령어를 통해 *.sh 파일을 실행할 수 있다. 실행 권한을 주면, ./*.sh 명령어로 직접 실행할 수 있다.

> sh test.sh

> ./test.sh

주석

#은 한 줄 주석이 되고, : '를 시작에, '를 마지막에 배치하면 여러 줄 주석이 된다.

# 한 줄 주석
: '
여러
줄
주석
'

혹은,

# 한 줄 주석
: <<"END"
여러
줄
주석
END

한 줄 주석만 사용하는 경우가 많다.


변수

  • 쉘 스크립트에서는 변수를 선언하지 않으며, 변수에 값이 할당되면 자동으로 생성된다.
  • 변수에 넣는 모든 값은 문자열로 취급한다. 공백이 있을 경우 ' 따옴표 혹은 " 쌍따옴표로 묶어야 한다.
  • 변수 이름은 대소문자를 구분한다.
  • 변수를 대입할 때 '=' 기호 좌우에 공백이 없어야 한다.
  • 변수를 사용하려면 $ 문자를 앞에 붙여야 한다.
  • 변수를 사용할 땐, 쌍따옴표로 묶는 것을 권장한다.
  • 변수 이름은 a to z, A to Z, 0 to 9 그리고 _ 언더스코어를 사용할 수 있다. 전부 대문자로 작성하는 것이 컨벤션이다.

test.sh

#!/bin/bash
VAR = hello
VAR=hello, world!
VAR='Hello, world!'
echo $VAR
STR=10+5
echo $STR
exit 0
> sh test.sh
test.sh: 3: VAR: not found
test.sh: 4: world!: not found
Hello, world!
10+5

C 언어처럼 printf 명령어를 사용할 수도 있다. echo와 달리, print 명령어는 자동 줄바꿈이 없다.

test.sh

#!/bin/bash
VAR="Hello, world!"
echo $VAR
echo "New Line"
printf "%s" "$VAR"
echo "No New Line"
exit 0
> sh test.sh
Hello, world!
New Line
Hello, world! No New Line

printf를 사용할 때, "$VAR"에서 " 쌍따옴표로 묶어주지 않으면 문자열의 공백을 표현하지 않으므로 주의해야 한다.

숫자 계산

변수에 넣은 값은 모두 문자열로 취급된다. 연산식으로 만들기 위해 $(expr expression) 형식으로 작성해야 한다. expr도 명령어이기 때문에 expression과 한 칸 띄어 써야 한다. 또한 expression에서 각 숫자와 연산자 마다도 띄어 써야 한다.

test.sh

#!/bin/bash
NUM1=10
NUM2=25
echo $(expr $NUM1+$NUM2)
echo $(expr $NUM1 + $NUM2)
exit 0
> sh test.sh
10+25
35

(, ), * 를 사용하려면 \ 역슬래쉬를 꼭 붙여야 한다.

test.sh

#!/bin/bash
NUM1=10
NUM2=25
echo $(expr \( $NUM1 + $NUM2 \) \* $NUM1)
echo $(expr \( $NUM1 + $NUM2 \) / $NUM1)
exit 0
> sh test.sh
350
3

expr 명령어는 소수점을 포함하지 않는다.

파라미터 변수

파라미터 변수는 $0, $1, $2 와 같은 형식을 가진다. 명령을 실행할 때 지정된다.

test.sh

#!/bin/bash
echo "실행 파일 이름: $0"
echo "\$1: $1"
echo "\$2: $2"
echo "\$3: $3"
echo "전체 파라미터: $*"
exit 0
> sh test.sh value1 value2 value3 value4
실행 파일 이름: test.sh
$1: value1
$2: value2
$3: value3
전체 파라미터: value1 value2 value3 value4

조건문

if문

각 단어 모두 공백이 있어야 한다. condition에 조건식을 작성한다.

if [ 조건 ]; then
  code
fi

[ ] 대신 test 키워드를 사용할 수 있다. 결과는 위와 동일하다.

if test 조건 ; then
  code
fi

if...else문

if [ 조건 ]; then
  조건 == true
else 
  조건 == false
fi

비교 연산자

문자열 비교 연산자와 산술 연산자가 있다. 단어마다 띄어쓰기 필수!

문자열 비교 연산자

문자열 비교결과
"문자열1" = "문자열2"두 문자열이 같으면 참
"문자열1" != "문자열2"두 문자열이 다르면 참
-z "문자열"문자열이 빈 문자열(NULL)이면 참
-n "문자열"문자열이 빈 문자열(NULL)이 아니면 참

산술 비교 연산자

산술 비교결과
수식1 -eq 수식2두 수식의 결과가 같으면 참
수식1 -ne 수식2두 수식의 결과가 다르면 참
수식1 -gt 수식2수식1이 크면 참
수식1 -ge 수식2수식1이 크거나 같으면 참
수식1 -lt 수식2수식1이 작으면 참
수식1 -le 수식2수식1이 작거나 같으면 참
!수식수식이 거짓이라면 참

파일을 처리하는 조건

파일 조건결과
-d 파일이름파일이 디렉토리면 참
-e 파일이름파일이 존재하면 참
-f 파일이름파일이 일반 파일이면 참
-g 파일이름파일에 set-gruop-id가 설정되면 참
-r 파일이름파일이 읽기 가능이면 참
-s 파일이름파일 크기가 0이 아니면 참
-u 파일이름파일에 set-user-id가 설정되면 참
-w 파일이름파일이 쓰기 가능 상태이면 참
-x 파일이름파일에 실행 가능 상태이면 참

case...case문

if 문은 참이나 거짓이냐에 따라 결정되므로 2가지의 경우의 수만 다룰 수 있다. case 문을 사용해 다수의 경우의 수를 다룰 수 있다.

case 변수 in
  case1)
    code
    ;;
  case2)
    code
    ;;
  case3)
    code
    ;;
  *)
    code
    ;;
esac

주의할 점은 각 case 마지막에 ;;를 꼭 붙여줘야 한다는 점이다.

case문을 활용할 때, 파라미터 변수에 의해 실행을 제어하거나, 실행 도중에 입력을 받아 제어할 수 있다. 그럴 땐, read 변수 명령을 통해 사용자의 입력을 기다릴 수 있다. -n 1enter 입력 없이 한 문자의 입력을 즉시 받고 싶을 때 사용한다.

test.sh

#!/bin/bash
printf "Do you want to download this package? [y/n]: "
read -n 1 ANSWER
echo
case $ANSWER in
y | Y)
  echo "Complete downloading"
  ;;
n | N)
  echo "Stop downloading"
  ;;
*)
  echo "Unexpected answer."
  exit 1
  ;;
esac
exit 0
> ./test.sh
Do you want to download this package? [y/n]: y
Complete downloading

> ./test.sh
Do you want to download this package? [y/n]: n
Stop downloading

> ./test.sh
Do you want to download this package? [y/n]: a
Unexpected answer.

exit 0는 정상적으로 종료되었을 때 지정되는 코드다. 의도치 않게 종료가 됐을 때 코드를 다르게 지정해서 종료된 이유를 확인할 수 있다.

AND, OR 관계 연산자

ANDOR
-a, &&-o, ||

-a-o는 테스트문([ ]) 안에서 사용할 수 있는데 괄호 등의 특수문자 앞에는 역슬래시를 꼭 붙여야 한다.


반복문

for...in문

값의 개수만큼 반복 실행할 수 있다.

for 변수 in 값1 값2 ...; do
  code using &변수
done

while문

조건식이 참인 동안 계속 반복하는 반복문이다.

while [ 조건 ]; do
  code
done

until문

조건식이 거짓인 동안 계속 반복하는 반복문이다.

until [ 조건 ]; do
  code
done

break, continue, exit, return

  • break: 해당 반복문을 종료한다.
  • continue: 진행을 멈추고 해당 반복문의 조건식으로 돌아간다.
  • exit: 해당 프로그램을 완전히 종료한다.
  • return: 함수 안에서 실행되며, 함수가 호출된 곳으로 돌아간다.

사용자 정의 함수

함수 작성과 호출

함수이름(매개변수) { ... } 형식으로 함수를 정의할 수 있고, 함수이름 인자로 호출할 수 있다.

func(매개변수) { # 함수를 정의
  code in function
  return
}

func 인자 # 함수를 호출

eval

문자열을 명령문으로 인식하고 실행한다.

test.sh

#!/bin/bash
EXEC="echo $1"
eval $EXEC
exit 0
> ./test.sh "Hello, shell script\!"
Hello, shell script!

전달받은 문자열을 명령문으로 인식하고 실행하는 코드는 보안상의 위험을 내포하기 때문에 공개된 환경에서는 사용하지 않는 것이 좋다.

export

외부 변수로 선언한다. 선언한 변수를 다른 프로그램에서도 사용할 수 있게 한다.

export externalVAR="외부 변수"

set과 $(명령)

리눅스 명령을 결과로 사용하려면 $(명령) 형식을 취해야 한다. 결과를 매개변수로 사용하고자 할 때는 set 명령과 함께 사용해야 한다. 기존의 매개변수를 덮어씌운다.

test.sh

#!/bin/bash
echo $(date)
set $(date)
echo "$1"
echo "$2"
echo "$3"
echo "$4"
echo "$5"
echo "$6"
echo "$*"
exit 0
> ./test.sh
Sat Apr 18 18:28:45 KST 2020
Sat
Apr
18
18:28:45
KST
2020
Sat Apr 18 18:28:45 KST 2020

shift

파라미터 변수를 왼쪽으로 한 단계씩 아래로 이동시킨다.

test.sh

#!/bin/bash
STR=""
while [ "$1" != "" ]; do
  STR="$STR $1"
  shift
done
echo $STR
exit 0
> ./test.sh a b c
a b c

1개의 댓글

comment-user-thumbnail
2022년 7월 4일

깔끔하네요. 익숙하지 않은 쉘 스크립트 쓸 때 참고하면 딱이겠어요!

답글 달기