공부 기록/리눅스 기초

[리눅스 기초] 12 쉘 스크립트(셸 스크립트) (1)

도도히히 2026. 1. 17. 14:49

셸의 기능과 종류

셸의 기능

  • 셸은 사용자와 커널 사이에서 중계자 역할을 수행하는 프로그램

셸의 종류

본 셸 (Bourne shell)

단순하고 처리 속도가 빠른 이유로 많이 사용됨

시스템 관리작업을 수행할 때 많은 스크립트는 본 셸을 기반으로 사용

sh 명령 사용

 

C 셸 (C shell)

본 셸의 기능 확장

에일리어스, 히스토리와 같은 사용자 편의 기능이 추가되어 제공됨

셸 스크립트 작성의 문법 형식이 C 언어와 비슷함

크기가 커지고 처리 속도가 느린 단점 등의 이유로 배시 셸에 밀림

csh 명령 사용

 

콘 셸 (Korn shell)

본 셸과의 호환성 및 편의 기능을 제공하면서 속도가 빠름

우분투 리눅스에서는 별도로 콘 셸을 설치하여 사용

ksh 명령 사용

 

배시 셸 (bash shell)

본 셸을 기반으로 개발된 셸, 본 셸과의 호환성을 유지하면서 C 셸, 콘 셸의 편리한 기능까지 제공

GPL(General Public License)을 따르는 공개 소프트웨어, 리눅스의 기본 셸로 제공 (우분투 리눅스에서도 O)

bash 명령 사용

 

대시 셸 (dash shell)

본 셀을 기반으로 개발됨, 포직스(POSIX) 표준을 준수하여 보다 작은 크기로 개발된 셸

부팅 시 셸 스크립트를 빠르게 실행시키며, 파일 크기가 작고 신뢰성이 높아 우분투 6.10 버전부터는 대시 셸을 시스템 기본 셸로 사용함

 

셸 스크립트 환경 변수

배시 셸의 주요한 환경변수

환경변수 의미 환경변수 의미

환경변수 의미 환경변수 의미
HOME 현재 사용자의 홈 디렉터리 PATH 실행 파일 찾는 경로
LANG 기본적으로 지원되는 언어 PWD 사용자의 디렉터리 위치
TERM 로그인 터미널 타입 SHELL 로그인에서 사용하는 셸
USER 현재 사용자의 이름 DISPLAY X 디스플레이 이름
COLUMNS 현재 터미널의 컬럼 수 LINES 현재 터미널 라인 수
PS1 1차 명령 프롬프트 변수 PS2 2차 명령 프롬프트(>)
BASH bash 셸의 경로 BASH_VERSION bash 버전
HISTFILE 히스토리 파일의 경로 HISTSIZE 히스토리 파일에 저장 개수
HOSTNAME 호스트 이름 USERNAME 현재 사용자 이름
LOGNAME 로그인 이름 LS_COLORS ls 명령의 확장자 색상
MAIL 메일을 보관하는 경로 OSTYPE 운영체제 타입

 

cf. 변수를 출력할 때 $를 붙여야 함

echo $HOME : 사용자의 홈 디렉터리 확인

echo $BASH_VERSION : bash 버전 확인

 

셸 변수 설정

사용자가 지정한 이름으로 설정할 수 있음

=을 사용하여 선언할 때 변수 이름과 문자열 사이에 공백이 존재해서는 안 됨

대/소문자 엄격하게 구별

 

변수 이름=문자열

ex) INSA=Hello

echo INSA : 변수명이 아닌 문자열로 취급하여 INSA가 출력됨

echo $INSA : 변수에 대입한 문자열인 Hello가 출력됨

 

환경변수 설정 명령 : export

먼저 셸 변수를 정의하고 export 명령을 사용하여 설정된 환경변수를 변경할 수 있음

‘export 환경변수=값’ 과 같이 선언할 수 O

export [옵션] [셸 변수] : 지정한 셸 변수를 환경변수로 변경하여 설정

옵션

-n : 환경변수를 셸 변수로 변경

cf. 환경변수 확인 : env | grep 변수명

export INSA : 셸 변수 INSA를 환경변수로 변경

export SPACE=key : 셸 변수를 선언하면서 곧바로 환경변수로 한번에 등록

 

환경변수를 셸 변수로 변경 : export -n

환경변수로 등록했던 셸 변수를 다시 셸 변수로 변경

export -n 환경변수

ex) export -n SPACE

 

셸 변수 해제 : unset

이미 정의된 셸 변수를 해제

unset 변수명

unset을 하면 echo $변수명 을 해도 아무 값이 출력되지 X

 

문제 12-01

  1. 셸 변수 DEPT를 선언하고 문자열 database를 대입하기
  2. DEPT 변수에 대입된 문자열 출력하기
  3. DEPT 변수를 환경변수로 전환하기
  4. 환경변수에 등록된 정보 출력하기
  5. 환경변수로 전환된 DEPT 변수를 다시 셸 변수로 전환하기
  6. 등록된 DEPT 셸 변수 해제하기
$ DEPT=database
$ echo $DEPT
$ export DEPT
$ env (혹은 쉽게 찾기 위해 env | grep DEPT)
$ export -n DEPT
$ unset DEPT

 


셸 스크립트의 특징

셸 출력 명령

공통 셸 출력 명령 : echo

모든 셸 스크립트 프로그래밍에서 공통으로 사용할 수 있는 출력 명령

echo [옵션] [문자열] : 화면에 한 줄의 문자열을 출력

옵션

-n : 문자열 중간에 선언하게 되면 선언한 위치에서 줄 바꿈을 수행

new line을 넣지 말아달라는 의미임 (아래 예시 참고)

-n을 어느 위치에 선언하느냐에 따라 출력결과가 다르게 나타날 수 있음

문자열 사이에 공백이 존재할 경우 문자열을 큰따옴표로 묶어줘야 함

ex) echo “I Love Ubuntu”

echo -n Nice : 옵션 지정으로 프롬프트 전에 문자열이 출력됨

NIce유저명@ubuntu:~$ ← 이런식으로 출력됨

 

출력형식 지정 명령 : printf

출력형식을 %d 지시자와 \n 줄바꿈 문자 등 C 언어에서 사용하는 출력함수인 printf() 함수의 형식을 지정하여 출력할 수 있음

printf [옵션] [문자열] : 출력형식을 지정하여 문자열을 출력

옵션

%d, \n 등 C언어의 printf()함수 형식을 지정

printf SPACE : 프롬프트 앞에 문자열이 출력됨 (SPACE유저명@ubuntu:~$)

printf “I Love \n Ubuntu” : Ubuntu를 다음 행으로 줄을 바꿔 출력 (두번째 줄: Ubuntu유저명@ubuntu:~$)

printf “%d + %d = %d \n” 30 50 80 : 30 + 50 = 80 출력

 


셸 스크립트 프로그래밍

셸 스크립트 작성과 실행

  • gedit을 사용하여 셸 스크립트 프로그래밍 수행
  • /sh_test.d : 셸 스크립트 파일을 저장할 디렉터리 생성 (디렉터리 명은 자유)
  • .sh : 셸 스크립트 파일임을 쉽게 구별하기 위해 확장자 선언 (확장자 선언은 자유)

 

셸 스크립트 작성 후 sh 명령으로 실행하기

gedit 또는 vi 에디터를 사용하여 작성

sudo mkdir /sh_test.d

cd /sh_test.d

sudo gedit myname.sh

#! /bin/sh

echo " Name Print "
echo ">> Connect Name : " $USERNAME

exit 0

#! : Shebang(셔뱅)이라고 함, 인터프리터 경로를 나타냄

#! /bin/sh : bash를 사용하는 의미 (생략하면 안 됨)

echo : 문자열 출력

$USERNAME : 현재 시스템에 접속된 사용자 이름을 출력하는 환경변수 선언

exit 0 : 종료 코드 (0은 성공 의미)

sh myname.sh : 셸 스크립트 파일 실행

 

변수 선언

  • 변수에 처음 값이 할당되면 변수는 자동으로 생성되므로 따로 변수를 선언하지 않음
  • 셸에서 사용하는 변수는 모두 문자열(String)으로 취급되므로 숫자 또한 문자열로 처리됨
  • 알파벳 대/소문자를 엄격하게 구별하며 변수의 값을 대입할 때는 ‘=’ 의 좌우에 공백이 존재해서는 안 됨

var1 = HI ← 오류: ‘=’ 좌우에 공백 있음

var2=good

var3=Nice day ← 오류: 두 개의 문자열인 경우 큰따옴표로 묶어야 함

var4=”Good morning”

var5=88+95 ← 오류는 없지만 연산은 안 됨(모두 문자열로 취급됨)

대입하는 값 사이에 공백이 있을 경우 반드시 큰따옴표로 묶기

변수에 값을 대입할 경우 이를 변수로 받기 위한 방법은 ‘$변수명’ 과 같이 변수명 앞에 $를 붙여주기

(변수임을 알리려고)

변수의 값에 공백 존재하지 않으면 $변수명, “$변수명” 상관 X

공백이 존재하면 무조건 “$변수명” 사용

 

변수의 입력과 출력

cd /sh_test.d

sudo gedit inout.sh

#! /bin/sh

echo " Q. Input : "
read input_string
echo " A. Output : $input_string "

exit 0

read input_string : 키보드로 입력한 값을 변수 input_string에 저장하는 read 명령

 

숫자 계산

키워드 expr을 사용해야 함

역따옴표(`)와 expr을 공백 없이 붙여서 사용해야 함, 역따옴표로 expr 연산식과 같이 시작과 끝을 묶어줘야 함

cf. 연산식에서 괄호를 사용하려면 괄호 앞에 \를 반드시 붙여줘야 함

사칙연산(+, -, , /) 중에서 예외적으로 곱셈 연산() 앞에도 반드시 \를 붙여줘야 함

sudo gedit arithmetic.sh

#! /bin/sh

echo " >> first : "
read a
echo " >> second : "
read b
echo " >> a = $a, b = $b "

add=`expr $a + $b`
gob=`expr $a \\* $b`
na=`expr $a / $b`
avg=`expr $add / 2`
echo " a + b = $add \\n a * b = $gob \\n a / b = $na \\n (a+b)/2 = $avg "

exit 0

sh arithmetic.sh : 셸 스크립트 실행

 

파라미터 변수

자신이 실행한 명령어의 파라미터(매개변수)를 의미함

$0, $1, $2, … 등과 같이 실행하는 명령의 부분을 각각 하나씩 변수로 지정

ex) dnf -y install xinetd 명령을 실행한다고 가정할 때 파라미터 변수

구분 수행할 명령 파라미터1 파라미터2 파라미터3
명령어 dnf -y install xinetd
파라미터 변수 $0 $1 $2 $3
표현 방법 $0 ← dnf $1 ← -y $2 ← install $3 ← xinetd

 

sudo gedit mapping.sh

#! /bin/sh

echo " >> One : $0 "
echo " >> Two : $1 "
echo " >> Three : $2 "
echo " >> Total : $* "

exit 0

echo “ >> Total : $* “ : 전체 파라미터 출력 (*는 전체를 의미)

sh mapping.sh 35 87 text_string

cf. text string 처럼 공백을 넣고 싶을 때 “text string” 입력, 큰따옴표 없이 입력하면 별개의 단어로 취급

 

문제 12-02

  1. 셸 스크립트 프로그램 test_1302.sh 작성하기
  2. 두 개의 변수 su1, su2를 선언하기
  3. su1 변수에 키보드로 23을 입력하여 저장하기
  4. su2 변수에 키보드로 56을 입력하여 저장하기
  5. 두 수의 곱을 변수 gob에 저장하기
  6. 키보드로 입력받은 값 출력하기
  7. 두 수의 곱셈 연산과 결과값 출력하기
$ gedit test_1302.sh

//셸 스크립트
#! /bin/sh
echo "1. 첫 번째 정수 입력"
read su1
echo "2. 두 번째 정수 입력"
read su2
echo ">> 두 수의 곱셈연산 결과"
gob=`expr $su1 \\* $su2`
echo " $su1 * $su2 = $gob "
exit 0

$ sh test_1302.sh

 


조건문과 관계 연산자

기본 if 문

주어진 조건이 참일 경우에만 수행하는 분기문으로 거짓일 경우에는 해당 명령을 수행하지 X

조건문을 묶는 대괄호 [] 안에 조건식을 선언할 때 각 단어와 연산자 사이에는 반드시 공백이 존재해야 함

 

1. 단일 조건 (if ~ then ~ fi)

if [ 조건식 ]; then

명령

fi

또는

if [ 조건식 ]

then

명령

fi

 

2. 이분 조건 (if ~ then ~ else ~ fi)

if [ 조건식1 ]; then

명령1

else

명령2

fi

cf. 1번처럼 ;를 쓰지 않고 then을 다음 줄로 보낼 수 있음

 

3. 다중 조건

if [ 조건식1 ]; then

명령1

elif [ 조건식2 ]; then

명령2

else

명령3

fi

(이때 elif는 여러 개 올 수 있음)

 

 

기본 if문 예시

sudo gedit basicif.sh

#! /bin/sh

if [ "space" = "space" ] 
then
	echo ">> compare : space = space ?? "
	echo ">> result : True "
fi

exit 0

sh basicif.sh

echo “>> compare : space = space ?? “ : 여기서 물음표는 특별한 의미 없음

 

if~else문 예시

sudo gedit ifelse_01.sh

#! /bin/sh

echo ">> compare : space != space ?? "
if [ "space" != "space" ]
then
	echo ">> result : True "
else
	echo ">> result : False " 
fi

exit 0

sh ifelse_01.sh

False가 출력될 것

 

 

비교 연산자

문자열 비교 연산자

연산자 의미 사용 예 결과
= 같음 “문자열1” = “문자열2” 두 문자열이 같으면 참
!= 같지 않음 “문자열1” != “문자열2” 두 문자열이 같지 않으면 참
-n Null이 아닌 값 -n “문자열” 문자열이 빈 문자열이 아니면 참
-z Null 값 -z “문자열” 문자열이 빈 문자열이면 참

 

산술 비교 연산자

연산자 의미 사용 예 결과
-eq 같음 변수1 -eq 변수2 변수1과 변수2가 같으면 참
-ne 같지 않음 변수1 -ne 변수2 변수1과 변수2가 같지 않으면 참
-gt 큼 (초과) 변수1 -gt 변수2 변수1이 변수2보다 크면 참
-ge 크거나 같음 (이상) 변수1 -ge 변수2 변수1이 변수2보다 크거나 같으면 참
-lt 작음 (미만) 변수1 -lt 변수2 변수1이 변수2보다 작으면 참
-le 작거나 같음 (이하) 변수1 -le 변수2 변수1이 변수2보다 작거나 같으면 참
! 부정 !변수1 변수1이 아니면 참

 

예제

sudo gedit ifelse_02.sh

#! /bin/sh

echo " >> compare : 300 -gt 800 ?? "
if [ 300 -gt 800 ] 
then
	echo " >> result : True "
else
	echo " >> result : False "
fi

exit 0

sh ifelse_02.sh

 

 

파일 관련 조건

연산자 결과

연산자 결과
-d 파일 이름 주어진 파일 이름이 디렉터리이면 참
-e 파일 이름 주어진 파일 이름이 존재하면 참
-f 파일 이름 주어진 파일 이름이 일반 파일이면 참
-g 파일 이름 주어진 파일 이름이 set-group-id가 설정되면 참
-r 파일 이름 주어진 파일 이름이 읽기가 가능하면 참
-s 파일 이름 주어진 파일의 크기가 0이 아니면 참
-u 파일 이름 주어진 파일 이름이 set-user-id가 설정되면 참
-w 파일 이름 주어진 파일 이름이 쓰기 가능한 상태이면 참
-x 파일 이름 주어진 파일 이름이 실행 가능한 상태이면 참

cf. setuid를 하면 파일 권한에서 -rws와 같이 원래 x가 써져있을 자리에 s가 들어감

 

예제

sudo gedit ifelse_03.sh

#! /bin/sh

sample=/lib/systemd/system/udev.service
if [ -f $sample ]
then
	echo " >> result : True "
	head -3 $sample
else
	echo " >> result : False "
fi

exit 0

sh ifelse_03.sh

head -3 $sample : 앞에서부터 3줄 출력

 

 

case~esac 문

if~else문은 조건이 많아지게 되면 구문이 복잡해지는 단점 존재

if~else문은 조건을 참과 거짓으로 판별하여 참과 거짓에 해당하는 명령을 수행

case~esac문은 여러 개의 조건을 펼쳐놓고 어느 조건에 해당되는지를 판별하여 명령을 수행하는 방식으로 구문 전개

  • case~esac 문법구조

case 파라미터 또는 키보드 입력값 in

조건1)

명령1;;

조건2)

명령2;;

조건n)

명령n;;

*)

앞에서 주어진 조건 이외의 모든 경우 실행할 명령;;

esac

 

cf. 명령 끝에 ;; 를 붙이는 이유: case문 탈출하기 위함

 

예제

sudo gedit case_01.sh

#! /bin/sh

echo " >> season choice : Spring / Summer / Fall / Winter "
case "$1" in
	Spring)
		echo " >> choice : Spring ";;
	Summer)
		echo " >> choice : Summer ";;
	Fall)
		echo " >> choice : Fall ";;
	Winter)
		echo " >> choice : Winter ";;
	*)
		echo " No choice ~ ";;

sh case_01.sh Spring

sh case_01.sh exit

 

키보드로 Yes 또는 No를 입력하거나 Y 또는 y 그리고 알파벳 n 또는 N으로 시작하는 모든 단어가 입력될 경우 해당 조건을 수행하도록 *를 함께 사용하여 조건을 선언하는 프로그램

 

예제

sudo gedit case_02.sh

#! /bin/sh

echo " >> state choice : (Yes / No / Y / N) "
read mind
case $mind in
	Yes | YES | yes | Y | y)
		echo " >> choice : Yes "
		echo " >> result : Linux Master ";;
	[nN]*)
		echo " >> choice : No "
		echo " >> result : Good Luck~ ";;
	*)
		echo " >> choice error !! ";;
esac

exit 0 

sh case_02.sh

[nN]* : n또는 N으로 시작 (n, N만있어도 됨)

;; 이 없을 경우 case문을 빠져나오지 않고 그 다음 줄로 커서를 이동시킴

Yes | YES | yes | Y | y) : 5개 중 하나에 해당하면 됨(or 연산)

 

 

조건문에서의 관계 연산자

 

- and 연산

if [ 조건1 ] && [ 조건2 ]

if [ 조건1 -a 조건2 ]

 

- or 연산

if [ 조건1 ] || [ 조건2 ]

if [ 조건1 -o 조건2 ]

 

예제

sudo gedit ifandor.sh

#! /bin/sh

echo ">> Search Name : "
read file_name
if [ -f $file_name ] && [ -s $file_name ]; then
	echo ">> File Select : $file_name "
	head -3 $file_name
else
	echo ">> Search File : $file_name "
	echo ">> File not found "
fi

exit 0

sh ifandor.sh

echo “>> Search Name : “ 과 read file_name을 한 줄로 병합하면,

read -p “Search Name : “ file_name 이라고 함

(ppt에는 없는 문제) - 일반 파일 혹은 디렉터리일 때 파일 이름 출력 (-o 옵션 이용)

#! /bin/sh

read -p "Search name: " file_name

if [ -f $file_name -o -d $file_name ]; then
	echo ">> File Select : $file_name "
else
	echo ">> Search File : $file_name "
	echo ">> File not found "
fi

exit 0

 

문제 12-03

  1. 셸 스크립트 프로그램 test_1303.sh 작성하기
  2. 명령 수행 파라미터 $1 사용하기
  3. 혈액형을 알파벳 대/소문자 구별 없이 A, B, O, AB 조건으로 정하기
  4. 혈액형 이외의 알파벳에 대해서는 다시 입력하기
  5. 혈액형에 대해서는 출력 메시지는 “무슨 형을 선택하였습니다.”로 출력하기
  6. 마지막에는 “프로그램을 종료합니다.”를 출력하기
$ gedit test_1303.sh

#! /bin/sh
echo ">> 명령 수행 파라미터 (A, B, O, AB)"

case "$1" in
A | a)
echo "A형을 선택하였습니다." ;;
B | b)
echo "B형을 선택하였습니다." ;;
O | o)
echo "O형을 선택하였습니다." ;;
AB | ab)
echo "AB형을 선택하였습니다." ;;
*)
echo "혈액형은 알파벳 대/소문자 구별 없이 A, B, O, AB만 가능합니다." ;;
esac
echo "프로그램을 종료합니다." 
exit 0

$ sh test_1303.sh