이것이 우분투 리눅스다 의 쉘 스크립트 프로그래밍 챕터를 정리한 내용입니다.
쉘은 사용자가 입력한 명령을 해석해 커널에 전달하거나, 커널의 처리 결과를 사용자에게 전달하는 역할을 한다.
쉘 명령문은 명령문과 함께 여러 옵션과 인자를 함께 사용할 수 있다.
(프롬프트) 명령 [옵션...] [인자...]
> 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
는 dash
를 가리키고 있는데 기능이 한정되어 있으므로 제대로 기능이 풍부한bash
를 사용하려면 #!/bin/bash
로 수정하면 된다.
쉘 스크립트 파일의 확장자는 .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
한 줄 주석만 사용하는 경우가 많다.
'
따옴표 혹은 "
쌍따옴표로 묶어야 한다.'='
기호 좌우에 공백이 없어야 한다.$
문자를 앞에 붙여야 한다._
언더스코어를 사용할 수 있다. 전부 대문자로 작성하는 것이 컨벤션이다.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
각 단어 모두 공백이 있어야 한다. condition
에 조건식을 작성한다.
if [ 조건 ]; then
code
fi
[ ]
대신 test
키워드를 사용할 수 있다. 결과는 위와 동일하다.
if test 조건 ; then
code
fi
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 파일이름 | 파일에 실행 가능 상태이면 참 |
if 문은 참이나 거짓이냐에 따라 결정되므로 2가지의 경우의 수만 다룰 수 있다. case 문을 사용해 다수의 경우의 수를 다룰 수 있다.
case 변수 in
case1)
code
;;
case2)
code
;;
case3)
code
;;
*)
code
;;
esac
주의할 점은 각 case 마지막에 ;;
를 꼭 붙여줘야 한다는 점이다.
case문을 활용할 때, 파라미터 변수에 의해 실행을 제어하거나, 실행 도중에 입력을 받아 제어할 수 있다. 그럴 땐, read 변수
명령을 통해 사용자의 입력을 기다릴 수 있다. -n 1
은 enter
입력 없이 한 문자의 입력을 즉시 받고 싶을 때 사용한다.
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 |
---|---|
-a, && | -o, || |
-a
나 -o
는 테스트문([ ]
) 안에서 사용할 수 있는데 괄호 등의 특수문자 앞에는 역슬래시를 꼭 붙여야 한다.
값의 개수만큼 반복 실행할 수 있다.
for 변수 in 값1 값2 ...; do
code using &변수
done
조건식이 참인 동안 계속 반복하는 반복문이다.
while [ 조건 ]; do
code
done
조건식이 거짓인 동안 계속 반복하는 반복문이다.
until [ 조건 ]; do
code
done
break
: 해당 반복문을 종료한다.continue
: 진행을 멈추고 해당 반복문의 조건식으로 돌아간다.exit
: 해당 프로그램을 완전히 종료한다.return
: 함수 안에서 실행되며, 함수가 호출된 곳으로 돌아간다.함수이름(매개변수) { ... }
형식으로 함수를 정의할 수 있고, 함수이름 인자
로 호출할 수 있다.
func(매개변수) { # 함수를 정의
code in function
return
}
func 인자 # 함수를 호출
문자열을 명령문으로 인식하고 실행한다.
test.sh
#!/bin/bash EXEC="echo $1" eval $EXEC exit 0
> ./test.sh "Hello, shell script\!"
Hello, shell script!
전달받은 문자열을 명령문으로 인식하고 실행하는 코드는 보안상의 위험을 내포하기 때문에 공개된 환경에서는 사용하지 않는 것이 좋다.
외부 변수로 선언한다. 선언한 변수를 다른 프로그램에서도 사용할 수 있게 한다.
export externalVAR="외부 변수"
리눅스 명령을 결과로 사용하려면 $(명령)
형식을 취해야 한다. 결과를 매개변수로 사용하고자 할 때는 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
파라미터 변수를 왼쪽으로 한 단계씩 아래로 이동시킨다.
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
깔끔하네요. 익숙하지 않은 쉘 스크립트 쓸 때 참고하면 딱이겠어요!