February 13, 2021

Shell Script 문법 정리

Title: Bash Shell Script 문법 정리
Author: DongDongE
Tags: Programming
Release: 2021.02.08


[Shell Script: Shell Script란??]


이번 기회에 블로그 포스팅으로 쉘스크립트에 대해 작성해보고자 한다...
맥북, 우분투 서버, NAS 서버 등 에서 ESXI를 자동 백업 스크립트를 작성하여 자동으로 관리 하려고 한다. 그렇게 하기 위해 서로 공통적으로 쉽게 호환되는 쉘 스크립트로 작성할겸 공부도 해볼려고 한다. (파이썬으로 작성 하려고 했으나 호환성 문제가 발생했음.)

무튼, 이번 기회에 쉘 스크립트 공부 내용을 올려본다.

Shell Script란??


Shell Script는 Shell이나 command line 인터프리터에서 구동되도록 작성된 스크립트다.
리눅스와 유닉스에서는 Shell Script라는 단어를 사용하지만, 윈도우에서는 batch(배치파일, .bat)이 사용되며 서로 다른 문법으로 작동된다.

즉, 한마디로 정리를 한다면, 여러 명령어들이 나열된 스크립트 파일이 자동으로 실행 또는 행위를 수행함으로 효율적이면서 간편하게 수행할 수 있다. (대신 그만큼 스크립트 코딩하는 것도 문제다...)

또한 Shell Script가 Interpreter 방식이므로, 한줄 한줄 읽어 실행함으로 다소 속도가 느리다.



Shebang (셔뱅? 쉬뱅? 이란?)


Shebang은 CLI에서 실행시키는 스크립트의 맨 처음 온다. shebang이 있는 스크립트는 프로그램으로 실행되면, 프로그램 로더가 스크립트의 첫 줄의 부분을 인터프리터 지시자로 구문을 분석한다.

#!/bin/bash
#!/bin/csh
#!/bin/zsh
....

위와 같이 인터프리터의 절대경로는 기입하면 된다.

#!/bin/zsh

echo $(which zsh)

1.sh

$ chmod +x 1.sh
$ ./1.sh
/usr/local/bin/zsh

위와 같이 "1.sh" 쉘 스크립트 파일을 생성하여 chmod 명령으로 모두 실행권한을 할당하여 실행한다. 실행후 zsh의 절대경로를 알 수 있게 된다.



변수 선언


변수의 타입에는 "로컬변수"와 "환경변수(전역)"이 존재한다.
로컬 변수는 말그대로 생성된 쉘에서만 사용이 가능하지만, "환경변수(전역변수)"는 생성된 쉘로 부터 자식으로 생성된 자식 프로세스에게도 접근할 수 있다.

  • 변수는 대,소문자를 구별한다.

  • 변수의 이름은 숫자를 포함할 수 있지만, 숫자로 시작할 수 없다.

  • 변수에는 모든 값을 문자열로 저장된다.

  • 변수에는 자료형을 기입하지 않는다. (Ex. int number, char names[10]), 즉 아무런 값을 다 넣을 수 있다.

  • 값을 사용할 때는 변수명 앞에 특수문자 "$"를 사용한다. (Ex. echo ${data})

  • 값을 대입(삽입)할 때는 특수문자 "$"를 사용하지 않는다. (Ex. data=mac)

  • 변수를 생성할 때는 "=" 대입문자 앞뒤로 공백이 없어야 한다. (Ex. data="abcd")



환경 변수

쉘이 작동되면 기본적으로 셋팅되어있는 변수들이다.

  • $0 - 실행된 쉘 스크립트 파일명

  • $# - 스크립트에 전달된 인자의 갯수

  • $$ - 쉘 스크립트의 PID


#!/bin/bash

echo $0
echo $#
echo $$

- code.sh -


$ chmod +x code.sh
$ ./code.sh
./code.sh
0
54639

- "code.sh" 실행 결과 -



인자 변수

쉘스크립트 작동시 인자로 넘겨주는 정보를 가지고 있는 변수다.

  • $1, $2, $3, $n... - 념겨진 인자의 값

  • $* 또는 $@ - 전달된 인자들을 모아놓은 문자열


#!/bin/bash

echo "Args 1: $1"
echo "Args 2: $2"
echo "Args 3: $3"

echo "Args List \$@: $@"
echo "Args List \$*: $*"

$ ./code.sh aa bb cc
Args 1: aa
Args 2: bb
Args 3: cc
Args List $@: aa bb cc
Args List $*: aa bb cc




산술 연산


쉘 스크립트의 변수 산술연산은 다른 언어의 비해 쉽지 않다. 위 "변수 선언" 파트 부분에서 나왔듯이 변수의 저장된 값은 문자열로 처리가 되므로 아무리 연산을 하고 싶어도 할 수 가 없다. 하지만 리눅스의 함수를 이용하여 산술 계산을 할 수 있다.


#!/bin/bash

number1=10
number2=20

plus=`expr $number1 + $number2`
minus=`expr $number1 - $number2`
mul=`expr $number1 \* $number2`
div=`expr $number1 / $number2`
rem=`expr $number1 % $number2`

echo "plus:     ${plus}"
echo "minus:    ${minus}"
echo "mul:      ${mul}"
echo "div:      ${div}"
echo "rem:      ${rem}"

- code.sh -


$ ./code.sh aa bb cc
plus:     30
minus:    -10
mul:      200
div:      0
rem:      10

차례대로 보면, 리눅스 프로그램인 "expr"를 사용하여 연산을 진행한다.
연산자 중 곱셈은 역슬래쉬"\"를 삽입하여 "\*"으로 진행한다.




IF 조건문


흐름상 조건문이 필요할 때 사용된다. 형식은 아래와 같다.
꼭!! 주의해야할 것은, if문 뒤에 나오는 "[", "]" 사이에는 공백이 존재해야 한다.

if [ 값1 조건식 값2 ]; then
    수행
fi

#!/bin/bash
num1=10
num2=10

if [ ${num1} -eq ${num2} ]; then
    echo "변수의 값이 같습니다."
fi

- code.sh -


$ ./code.sh
변수의 값이 같습니다.

위 쉘스크립트 코드의 로직은 변수 "num1"와 "num2"의 값이 같으면 "-eq" 아래 조건문 대로 echo 함수가 작동된다.

이 외에도 조건문 비교 종류는 아래와 같이 존재합니다.

[ -z ${변수A} ] # 변수A의 문자열 길이가 0이면 True
[ -n ${변수A} ] # 변수A의 문자열 길이가 0이 아니면 True

[ ${변수A} -eq ${변수B} ] # 변수A와 변수B의 값이 같으면 True
[ ${변수A} -ne ${변수B} ] # 변수A와 변수B의 값이 다르면 True
[ ${변수A} -gt ${변수B} ] # 변수A의 값이 변수B보다 크면 True
[ ${변수A} -ge ${변수B} ] # 변수A의 값이 변수B보다 크거나 같으면 True
[ ${변수A} -lt ${변수B} ] # 변수A의 값이 변수B보다 작으면 True
[ ${변수A} -le ${변수B} ] # 변수A의 값이 변수B보다 작거나 같으면 True

[ 조건A -a 조건B ] # 조건식 A와 B모두가 참이면 True (&& 연산자)
[ 조건A -o 조건B ] # 조건식 A가 참이거나 조건식 B가 참일 경우 True (|| 연산자)

# 아래는 파일 관련 조건문 종류
[ -d ${A} ] # A파일이 디렉터리면 True
[ -e ${A} ] # A파일이 존재하면 True
[ -L ${A} ] # A파일이 심볼릭 링크로 되어 있으면 True
[ -r ${A} ] # A파일이 읽기가 가능하면 True
[ -w ${A} ] # A파일이 쓰기가 가능하면 True
[ -x ${A} ] # A파일이 실행이 가능하면 True
[ -s ${A} ] # A파일의 크기가 0보다 크면 True
[ ${A} -nt ${B} ] A파일이 B파일보다 최신파일이면 True
[ ${A} -ot ${B} ] A파일이 B파일보다 이전파일이면 True
[ ${A} -ef ${B} ] A파일이 B파일이랑 같은 파일이면 True

위 조건문의 비교하는 방법을 알아보았지만, 문자로된 조건식은 어려워서 아래의 방법을 추천한다.

if [ ${num1} < ${num2} ]; then
    echo "yes"
else
    echo "No"
fi

프로그램 코딩처럼 기호를 써서 작업하자...



단일 IF문

#!/bin/bash

num1="10"
num2="11"

# 1
if [ ${num1} -lt ${num2} ]; then
    echo "yes"
fi

# 2
if [ ${num1} -lt ${num2} ]
then
    echo "yes"
fi

# 3 - 조건문을 문자 대신 기호로 표현
if (( ${num1} < ${num2} )); then
    echo "yes"
fi

# 4 - 한줄로 작성
if [ ${num1} -lt ${num2} ]; then echo "yes"; fi

위와 같이 쉘 스크립트에서 조건문을 작성하는 방법은 여러가지가 있다. 결과와 로직흐름은 서로 같다


bash-3.2$ ./code2.sh
yes
yes
yes
yes



IF-ELSE문

"if-else" 구문은 해당 조건식에 의해 참 또는 거짓일 경우 각각 로직 흐름을 맞출 수 있다.


#!/bin/bash

num1="11"
num2="10"

# 1
if [ ${num1} -lt ${num2} ]; then
    echo "yes"
else
    echo "no"
fi

# 2
if [ ${num1} -lt ${num2} ]
then
    echo "yes"
else
    echo "no"
fi

# 3 - 조건문을 문자 대신 기호로 표현
if (( ${num1} < ${num2} )); then
    echo "yes"
else
    echo "no"
fi

# 4 - 한줄로 작성
if [ ${num1} -lt ${num2} ]; then echo "yes"; else echo "no"; fi

위 코드를 살펴보면, 단순히 "if" 흐름도에서 "else"가 추가되어 어떻게 로직을 구현할지 작성만 하면 된다.



IF-ELIF문

"if-ELIF" 구문은 여러 IF문이 추가되 각 상황에 맞게 로직 흐름을 수행할 수 있다고 보면된다.


#!/bin/bash

num1="10"
num2="10"

# "-lt", A가 B보다 작으면 True
# "-eq", A와 B가 서로 같으면 True

if [ ${num1} -lt ${num2} ]; then
    echo "yes"
elif [ ${num1} -eq ${num2} ]; then
    echo "bbb"
else
    echo "no"
fi


if [ ${num1} -lt ${num2} ]
then
    echo "yes"
elif [ ${num1} -eq ${num2} ]
then 
    echo "bbb"
else
    echo "no"
fi


if (( ${num1} < ${num2} )); then
    echo "yes"
elif (( ${num1} == ${num2} )); then
    echo "bbb"
else
    echo "no"
fi


if [ ${num1} -lt ${num2} ]; then echo "yes"; elif [ ${num1} -eq ${num2} ]; then echo "bbb";  else echo "no"; fi



반복문 for

반복문은 여러 작업을 수행할 때 사용된다. 주로 "for"문과 "while" 문을 통하여 할 수 있다.

#!/bin/bash

for <변수> in <범위>
do
    <수행 로직>
done

형식은 위와 같다.



#!/bin/bash

data="1 2 3 4"

# 초기값; 조건값; 증가값을 사용한 반복문
for ((i=1; i<=4; i++)); do
    echo $i
done

# 변수를 사용한 반복문
for x in $data
do
    echo ${x}
done

# seq 함수를 사용한 반복문 (1, 2, 3, 4) 범위 나열
for x in $(seq 4)
do
    echo ${x}
done

# 배열을 사용한 반복문
datas=(1 2 3 4)
for x in $datas
do
    echo ${x}
done

또한 위 코드와 같이 여러 방법을 통한 반복문을 구현할 수 있다.