[부트캠프 - 19일차] 1/16.금 - Linux

developowl·2026년 1월 16일

부트캠프

목록 보기
10/24
post-thumbnail

Shell Programming(Script)

Shell Script

  • Unix나 Linux 또는 POSIX(Portable Operating System Interface)를 지원하는 Max OS 등에서 사용하는 명령어들과 if, for 과 같은 프로그래밍적인 요소로 이루어진 인터프리터 기반의 스크립트 언어

종류

  • sh - 셸 스크립트의 기반
  • bash - 리눅스에서 가장 많이 사용되는 셸로 본 셸을 기반으로 헤사 C 셸과 Korn 셸의 기능을 통합시켜 개발
  • ksh
  • csh
  • tcsh
  • zsh - bash와 tsch의 기능에 독자적인 기능을 추가

1) 생성 및 실행

  • 스크립트 만들기
    • 확장자는 sh를 사용
    • 시작할 때는 #!/bin/bash(shebang) 를 붙여서 해당 파일이 셸 스크립트라는 것을 알려줌
    • 실행하고자 하는 명령어를 입력하고 저장
    • 파일을 작성: myshell.sh
#!/bin/bash(shebang)

echo "Hello World!"
  • 실행
# 셸이름 경로
# 이렇게 실행할 때는 파일에 읽기 권한만 있으면 됨
sh myshell.sh
bash myshell.sh

파일을 이름을 가지고 직접 실행

  • 파일의 소유권한을 변경 - 실행 권한을 부여
  • 현재 디렉토리의 파일이라도 PATH에 존재하지 않는다면 ./ 를 붙여서 실행
chmod 751 myshell.sh

명령어를 셸에서 직접 수행

echo "Hello World!"

2) 변수 사용

  • 기본 변수 선언해서 문자열을 출력
    • 변수명=값 의 형태로 선언하는데 변수가 존재하면 수정
    • = 다음에 공백을 주면 명령어로 인식
  • 변수를 사용할 때는 $변수명
#!/bin/bash

language="Korean"

echo "Hello World!"
echo "I can speak $language"

# ---
# 실행
./myshell.sh

변수의 종류

함수)

# 생성
function 이름() {내용}
  • 내용을 작성할 때 파라미터를 사용하고자 하면 $번호 로 작성하는데 함수를 호출할 때 파라미터를 넘겨주면 순서대로 대입됨
  • 함수 호출을 할 때는 함수이름 파라미터 파라미터… 형식

전역 변수)

  • 함수 외부에 선언해서 모든 영역에서 사용 가능한 변수

지역 변수)

  • 함수 내부에서 선언해서 함수 내부에서만 사용 가능한 변수

환경변수)

  • 시스템을 위해 사전에 예약해두고 시스템에서 사용하고 있는 변수
  • 자주 사용하는 환경변수
    • HOME : 사용자의 홈 디렉토리
    • PATH : 실행 파일을 찾는 디렉토리 경로
    • PWD : 현재 작업 중인 디렉토리
    • USER : 현재 로그인한 사용자 이름
    • USERNAME : 현재 로그인한 사용자 이름
    • HOSTNAME : 현재 컴퓨터 이름

위치 매개변수)

  • 스크립트 수행 시 함께 넘어오는 파라미터
  • $0 : 스크립트 이름
  • $1 , $2 , ${10} : 파라미터 순서대로 번호가 부여되는데 10번째부터 {} 로 감싸야 함
  • $* : 전체 인자값
  • $@ : 전체 인자값, 쌍따옴표로 감싸면 다른 결과가 나옴
  • $# : 매개변수의 총 개수
#!/bin/bash

echo "$0"
echo "$1 and $2"
echo "$*"
echo "$@"
echo "$#" 

# 실행
./test1.sh Korea Newziland USA

특수 매개변수)

  • 실행 중인 스크립트나 명령어의 PID를 확인하거나 바로 앞에서 실행한 명령어나 함수 또는 스크립트 실행이 정상적으로 수행되었는지 여부를 확인할 수 있는 변수

  • $$ : 현재 스크립트 또는 명령어의 PID

  • $? : 최근에 실행된 명령어, 함수, 스크립트의 종료 상태

  • $! : 최근에 실행된 백그라운드 명령의 PID

  • $- : 현재 옵션 플래그

  • 이를 확인해서 현재 스크립트를 &를 이용해서 백그라운드로 수행할 지 결정할 수 있음

매개변수 확장)

  • 기본 변수 사용
  • $변수명 을 사용하는데 뒤에 공백없이 문자열을 붙여야 하는 경우 {} 를 이용해서 변수명을 구분할 수 있음
  • AUTH_URL 이라는 변수에 www.example.com/ 을 저장해두고 https://변수내용login.html 로 출력하고자 하는 경우
# 변수명 인식 불가
echo "https://$AUTH_URLlogin.html"

# 중괄호 사용
echo "https://${AUTH_URL}login.html"

변수를 초기화하기 위한 확장 변경자

  • ${변수-문자열} : 변수가 없으면 문자열로 치환
  • ${변수:-문자열} : 변수가 없거나 NULL 이면 문자열로 치환
  • ${변수=문자열} : 변수가 없으면 문자열을 변수에 저장하고 변수 치환
  • ${변수:=문자열} : 변수가 없거나 NULL 이면 문자열을 변수에 저장하고 변수 치환
  • ${변수+문자열} : 변수가 있는 경우 문자열로 변수 치환
  • ${변수:+문자열} : 변수가 설정되고 NULL이 아닌 경우 문자열로 변수 치환
  • ${변수?에러메시지} : 변수가 설정된 변수를 사용하고, 설정되지 않은 경우 표준 오류 출력으로 에러 메시지를 출력
  • ${변수:?에러메시지} : 변수가 설정되고 값이 NULL이 아니면 변수를 사용하고, 설정되지 않은 경우 표준 오류 출력으로 에러 메시지를 출력
  • ${변수:시작위치} : 변수 값이 문자열일 경우 시작 위치부터 문자열 길이 끝까지 출력
  • ${변수:시작위치:길} : 변수 값이 문자열일 경우 시작 위치부터 문자열 길이까지 출력
OS_TYPE=redhat
echo ${OS_TYPE-ubuntu} # OS_TYPE이 존재하므로 redhat
unset OS_TYPE # 변수 삭제
echo ${OS_TYPE-ubuntu} # OS_TYPE이 존재하지 않으므로 ubuntu를 
										# 출력하지만, OS_TYPE에 값이 대입되지는 않음
echo ${OS_TYPE}

unset OS_TYPE # 변수 삭제
echo ${OS_TYPE=ubuntu} # OS_TYPE이 존재하지 않으므로 ubuntu를
											# 출력하고 OS_TYPE에 값을 대입
echo ${OS_TYPE}

OS_TYPE="redhat"
echo ${OS_TYPE:?null or net set} # 변수에 값이 있으므로 변수의 값을 출력
OS_TYPE=""
echo ${OS_TYPE:?null or net set} # 변수에 값이 없으므로 메시지 출력, 비정상 종료
echo $?

치환

  • ${변수#패턴} : 패턴 앞의 모든 문자열 제거
  • ${변수##패턴} : 패턴을 찾아서 가장 마지막 패턴의 앞에 있는 모든 문자열을 제거
  • ${변수%패턴} : 패턴 뒤의 모든 문자열 제거
  • ${변수%%패턴} : 패턴을 찾아서 가장 마지막 패턴의 뒤에 있는 모든 문자열을 제거
  • ${#변수} : 문자열의 길이
  • ${변수/찾을 문자열/바꿀 문자열} : 첫번째 패턴을 뒤의 문자열로 치환
  • ${변수/#찾을 문자열/바꿀 문자열} : 시작 문자열이 일치하면 치환
  • ${변수/%찾을 문자열/바꿀 문자열} : 마지막 문자열이 일치하면 치환

${FILE_NAME#*_} : 첫 번째 구분자까지 제거

  • 앞에서부터 찾아서 첫 번째 _ 를 포함한 그 앞의 문자열을 제거
echo ${FILE_NAME#*_}

${FILE_NAME##*.} : 확장자만 남기고 모두 제거

  • 앞에서부터 찾아서 가장 마지막에 위치한 . 를 포함한 그 앞의 모든 문자열을 제거
echo ${FILE_NAME##*.}

${FILE_NAME%_*} : 마지막 _ 뒤를 제거

echo ${FILE_NAME%_*}

디렉토리 경로 출력

echo ${FILE_PATH%/*}

파일 이름만 출력

echo ${FILE_PATH##*/}

OS_TYPE=”Redhat Linux Ubuntu Linux Fedora Linux”

처음 찾은 Linux 를 OS로 변경

echo ${OS_TYPE/Linux/OS}

모든 Linux를 OS로 변경

echo ${OS_TYPE//Linux/OS}

OS를 삭제

echo ${OS_TYPE//Linux}

Red로 시작하는 단어를 Unknown으로 변경

echo ${OS_TYPE/#Red/Unknown}

tu로 끝나는 단어를 Debian으로 변경

echo ${OS_TYPE/%tu/Debian}

3) 조건문 - if, switch-case

if

if [첫번째 조건식]
then
	수행문
elif [두번째 조건식]
then 
	수행문
else
	수행문
fi
  • -z 연산자를 이용하면 문자열의 길이가 0인지 확인 가능
    • if [-z $value ] → value의 길이가 0인지
  • 크다와 작다는 -gt, -lt 로 표현

case

case $변수 in
	조건값)
	수행문
	;;
	조건값)
	수행문
	;;
	...
	*)
	수행문
esac

4) 반복문

for

for 변수 in [범위(리스트 또는 배열, 묶음)]
do
	수행문
done

# 예제
numbers="1 2 3"

for num $numbers
do
	echo $num
done
# 디렉토리 경로로 설정 - 디렉토리 내의 파일이나 디렉토리를 순회
for file in $HOME/*
do
	echo $file;
done

# {} 를 이용하면 중간 숫자를 생략하는 것이 가능, 대신에 중간에 ... 사용
for num in {1...5}
do
	echo $num;
done

# 배열 사용
array=("apple", "banana", "pineapple")

for fruit in ${array[@]}
do
	echo $fruit;
done

while

while [$변수 연산자 $변수2]
do
	반복할 문장
done

# 실습
num = 0

while [$num -lt 3]
do
	echo $num
	num = $((num+1+))
done

5) 연산자

문자열 연산자

  • -z : 문자열의 길이가 0이면 참
  • -n : 문자열의 길이가 0이 아니면 참
  • 숫자 비교 연산자
    • 부등호 : ( ) 안에서 사용
    • -eq, -ne, -gt, -lt, -ge, -le 사용 가능

문자열 비교 연산자

  • =, ==, !=, <, >

논리 연산자

  • -a : and 연산자
  • -o : or 연산자
  • &&: and 인데 이 연산자를 사용할 때는 각 조건식을 [ ] 나 [{ }] 를 사용
  • || : or 인데 이 연산자를 사용할 때는 각 조건식을 [ ] 나 [{ }] 를 사용
VAR1 = 10; VAR2=20; VAR3=30;
if [ $VAR1 -lt $VAR2 -a $VAR2 -gt $VAR3 ]
then
	echo True
else
	echo False
fi

디렉토리 연산자

  • -d : 변수 유형이 디렉토리라면 참
  • -e : 변수 유형이 디렉토리나 파일이라면 참

파일 연산자

  • -f : 파일 여부 확인
  • -L : 파일이면서 심볼릭 링크 여부 확인
  • -r : 파일이거나 디렉토리이면서 읽기 권한이 있으면 참
  • -w
  • -x
  • -s : 파일이거나 디렉토리이면서 사이즈가 0보다 크면 참
  • -O : 파일이거나 디렉토리이면서 스크립트 실행 소유자와 동일하면 참
  • -G : 파일이거나 디렉토리이면서 스크립트 실행 그룹이 동일하면 참
# 파일 여부 체크
ls -l /etc/localtime # /usr/share/zoneinfo/Etc/UTC

ls -l /usr/share/zoneinfo/Etc/UTC

FILE=/etc/localtime # 변수에 심볼릭 파일 링크 저장

# 현재 경로가 파일 경로가 맞는지 확인
if [ -f $FILE ]; then echo True; else echo False; fi

# 현재 경로가 심볼릭 링크 파일 경로가 맞는지 확인
if [ -L $FILE ]; then echo True; else echo False; fi

# 파일에 내용이 있는지 없는지 확인
touch smaple.txt

FILE=sample.txt

# 파일의 크기가 0이 아니면 True, 0이면 False
if [ -s $FILE ]; then echo True; else echo False; fi

파일 비교 연산자

  • -nt : 앞의 파일이 뒤의 파일보다 최신 파일이면 참
  • -ot : 이전 파일이면 참
  • -ef : 동일 파일이면 참

6) 정규 표현식

  • 리눅스나 유닉스의 특별한 특징을 부여하는 문자들과 메타 문자들의 집합
  • 정규 표현식을 알면 검색을 할 때 편리

메타문자

  • . : 줄바꿈을 제외한 한 개의 문자와 일치
  • ? : 자신 앞에 나오는 정규 표현식이 없거나 하나가 일치하는 것을 찾는데 대부분 한 개의 문자와 매칭할 때 사용
  • * : 바로 앞 문자열이나 정규 표현식에서 한 번 이상 반복되는 문자
  • + : * 과 유사하지만 반드시 하나 이상의 문자
  • {숫자} : 정확하게 N번
  • {숫자,} : N번 이상
  • {숫자1, 숫자2} : 숫자1 이상 숫자2 이하
  • - : 범위
  • ^ : 라인의 시작에서 공백 문자열을 의미하며 목록의 범위에 없는 문자열을 의미
  • $ : 라인의 끝에서 공백 문자열을 의미
  • ^$ : 빈줄
  • [ ] : 문자들의 집합
  • \(백슬래시) : 특수 문자를 원래의 문자 의미대로 해석
  • \b : 단어
  • \B : 줄

문자 클래스

  • [:alnum] : 알파벳이나 숫자
  • [:alpha:] : 알파벳
  • [:blank:] : 스페이스나 탭
  • [:cntrl:] : 제어문자
  • [:digit:] : 숫자
  • [:graph:] : 출력 가능한 문자
  • [:lower:] : 소문자
  • [:print:] : 출력 가능한 문자인데 스페이스 포함
  • [:punct:] : 문장 부호
  • [:space:] : 뉴라인 줄바꿈, 스페이스, 탭
  • [:upper:] : 대문자
  • [:xdigit:] : 숫자와 16진수 문자

정규 표현식 실습을 위한 파일을 다운로드 받아서 가상머신의 리눅스에 전송

# 터미널을 실행시켜서 파일을 SSH를 통해서 전송
# scp -P 포트번호 파일경로 계정@IP:저장할 경로
scp -P 22 /Users/shinji/Downloads/expression.txt developowl@192.168.64.2:/home/developowl/shell

# C로 시작하고 U로 끝나는 3글자 조회
grep 'C.U' expression.txt

# q로 시작해서 ?로 끝나는 단어이어야 하며 중간에는 영문 소문자만 존재하는 단어
grep -E 'q[[:lower:]]*\?' expression.txt
	# : ? 는 메타문자라서 \와 함께 사용해야 함
	# grep에서 클래스는 [[ ]] 안에 표현
	# 메타문자나 확장 클래스를 사용할 때 E 옵션을 이용하는 것이 좋음
	
# - 다음에 2가 1번 이상 나타나고 그 뒤에 -를 포함하는 문자열을 조회
grep -E '\-2+\-' expression.txt

# 알파벳 5글자로 시작하고 알파벳 뒤에 : 으로 끝나는 단어가 있는 라인을 검색
grep -E '^[[:alpha:]]{5}:' expression.txt

# 라인 시작 시 알파벳 5글자 이상이며 뒤에 공백을 가진 단어가 있는 라인을 조회
grep -E '^[[:alpha:]]{5,}[[:space]]' expression.txt

스크립트에서 많이 사용하는 명령

1) grep - 문자열 조회

grep [옵션] 패턴 [파일 경로]

# e는 한번에 여러 개의 정규식을 사용하겠다는 의미
# f는 패턴이 파일에 존재
grep [옵션] [-e 패턴 | -f 파일] [파일]

명령어 | grep [옵션] [패턴 | -e 패턴]
  • 옵션
    • E : 확장 정규 표현식
    • F : 여러 줄 문자열을 검색

2) find - 파일 찾기

find [대상 경로][표현식]

# /etc 디렉토리에 이름이 chrony.conf 파일을 조회
find /etc chrony.conf
  • 파일의 접근 권한이나 시간을 이용한 검색도 가능

3) awk - 특정 인덱스 문자열을 출력

  • csv 형식으로 되어있는 파일에서 특정 열의 데이터만 추출하는 것이 가능

4) sed - 찾은 문자열을 바꿈

# /etc/ssh/sshd_config 파일에서 #PermitRoot 를 찾아서 주석을 해제
sed 's/#PermitRoot/PermitRoot' /etc/ssh/sshd_config | grep '^#PermitRoot'
sed 's/#PermitRoot/PermitRoot' /etc/ssh/sshd_config | grep '^PermitRoot'

5) date - 날짜와 시간을 알려주는

date [옵션]

# date +포맷
date '+%Y-%m-%d %l.%M %p'
  • date : 현재 날짜를 설정된 로케일 형식으로 보여줌
  • date -d yesterday : 어제 시간을 보여줌

사용자 계정을 생성하는 스크립트를 만들어서 실행

1) 필요한 정보

  • 사용자 계정
  • 사용자 비밀번호
  • 관련 명령: useradd, passwd

2) 수행 과정

  • 사용자 계정과 패스워드를 입력 받음
  • 입력 정보가 없으면 에러 메시지를 출력하고 셸 스크립트를 종료
  • 여러 명의 사용자 계정을 생성하는 경우는 for 문을 사용
  • 기존 사용자 계정이 존재하는지 확인
  • 사용자 계정이 없으면 생성하고 패스워드 설정을 함
  • 사용자 계정이 존재하면 계정이 있다고 메시지를 출력

3) 스크립트 작성 adduser-srcipt.sh

#!/bin/bash
if [[ -n $1 ]] && [[ -n $2 ]]
then
	UserList=($1)
	Password=($2)
	
	# 세미콜론(;)으로 수정
	for (( i = 0; i < ${#UserList[@]}; i++ ))
	do
		# $(UserList[$i]} 를 ${UserList[$i]} 로 수정
		if [[ $(cat /etc/passwd | grep ${UserList[$i]} | wc -l) == 0 ]]
		then
			sudo useradd ${UserList[$i]}
			echo ${Password[$i]} | passwd ${UserList[$i]} --stdin
		else
			echo "this user ${UserList[$i]} is existing"
		fi
	done
	
else
	echo -e "Input User ID and Password\n\"user01 user02\" \"pw01 pw02\""

fi
profile
Don’t get mad at the computer.

0개의 댓글