Contents

Linux Shell Scripting

개요

  • 사용자와 OS 간의 간교 역할
  • Linux에서 기본적으로 사용하는 shell은 bash
  • 복잡한 일들 -> 작은 단위 나누어 처리
  • 여러 요소들과 유틸을 묶어 처리하는 고전적인 유닉스 철학
  • #!는 스크립트를 해석할 프로그램을 지정하는 역할
  • 반복되는 일련의 커맨드나 유틸 실행 작업을 묶어서 한번에 처리

기본 문법

리다이렉션

  • Shell의 표준 입출력 (STDIN, STDOUT, STDERR)을 제어
  • ‘<, >, »’ 등의 기호 사용하여 리다이렉션
  • 입력은 키보드, 출력은 터미널 화면
  • 리다이렉션 통해 결과를 파일에 출력하거나 입력을 파일에서 받도록 변경 가능

‘>’ : 파일을 새로 생성하여 표준 출력을 저장 (write) ‘»’ : 파일이 존재한다면 끝에 추가한다 (append) ‘<’ : 파일의 내용을 불러온다 (read) ‘2>’ : 표준 에러를 리다이렉션 ‘>&’ : 표준 출력, 표준 에러 모두 리다이렉션 ‘>!’ : 파일의 존재 유무와 상관 없이 생성하여 저장 ‘2> & 1’ : 표준 에러를 표준 출력으로 리다이렉션 ‘<>’ : 디바이스 파일이라면 표준 입력과 표준 출력으로서 파일 사용

cron으로 쉘 스크립트 실행할 때 출력 리다이렉트 하지 않으면 결과가 계속 발송됨

cron의 스크립트는 파일이나 /dev/null로 리다이렉트하는 것이 필요

파이프

프로그램, 명령어의 출력을 다른 명령어나 프로그램의 입력으로 전환하는 기능. 선행 프로그램에서 출력한 결과를 후행 프로그램의 입력으로 하는데 사용

예제 1. ps aux | grep ssh 예제 2. ls | xargs cat

변수

  • 변수 이름은 대소문자 구분
  • ‘=‘으로 값을 지정
  • Shell에서는 변수 사용하기 위해 미리 선언 X
  • 최초로 사용될 때 자동 할당

특수변수

  • $@과 $*는 비슷하지만 "로 감싸져 있을때 의미가 달라짐
  • $*는 큰 따옴표로 감싸면 여러 개의 인자들이 하나의 문자열이 됨
  • $@는 큰 따옴표 없이는 $*와 동일하지만 큰 따옴표로 감싸면 각 인자 하나하나를 따옴표로 감싸는 효과
  • 인자에 공백 넣고 싶을 때에는 “$@” 형식으로 사용

지역변수

일반적인 변수로 현재 스크립트 내부에서만 사용, 스크립트 종료 시 변수 해제. 자식 프로세스에 전달되지 않음

전역변수

실행 중인 Shell로부터 생성되는 자식 프로세스도 사용가능 Shell의 환경 변수를 의미 전역 변수도 현재 스크립트 / Shell이 종료되면 사용 불가

인자

  • 스크립트 실행 시 스크립트 이름 뒤 붙여져서 전달되는 값들
  • 인자 값은 주어진 순서대로 $1 ~ $9, ${10}, ${11} … 변수들에 저장
  • 쉘 스크립트 이름 자체는 0번째 인자인 $0
  • 다음 첫번째 인자가 $1

변수

  • 하나의 변수 이름에 단어, 숫자로 구성된 목록의 배열로 지정 가능
  • 내장 함수 선언 가능, 직접 배열 할당 방식도 가능
  • 배열의 구성 값은 “$배열 변수명[index]” 형식 사용

if문

  • 주어진 조건식의 결과값이 true / false 인지에 따라 분기
  • if / then은 명령어 목록의 종료 상태가 0 인지 테스트 해보고 맞다면 다음 명령어 실행
    • 리눅스 관례 상 0은 성공
  • if ,if else, if elif else 등의 형식으로 사용

case 문

  • 복잡한 if then elif else 구문 대신할 수 있음
  • case 문의 변수 값이 조건에 매칭되는 위치의 명령 블록 실행
    • *) 조건은 모든 값과 매칭
  • 명령 블록은 더블 세미콜론 (;;)을 만나기 전까지 실행

테스트 연산자

전용 내장 명령어인 [로 사용 가능. 자신의 인자를 비교식이나 파일 테스트로 인식 해당 연산의 결과에 따른 종료 상태 (참은 0, 거짓은 1)을 리턴

while 문

조건식이 true이면 루프 실행 변수 값을 수정하면서 false가 될 때까지 반복 수행하도록 할 때 사용

for 문

while 과 비슷하지만 괄호 안에 초기화 표현식, 테스트 표현식, 변수 업데이트 표현식이 모두 들어감 주어진 리스트 값들을 하나씩 대입하면서 실행하는 형식도 있음

break 문

  • 루프문 실행 도중 break를 만나면 로프의 실행 블록 영역 탈출
  • 해당 루프문을 강제로 종료시킬 때 사용
  • 여러 개의 중첩 루프가 있을 때는 break n 과 같이 숫자를 덧붙여 원하는 위치로 루프를 빠져나가도록 할 수 있음

continue 문

  • 루프문 실행 도중 continue 만나면 그 이하의 실행 블록을 수행하지 않고 루프 초기 위치로 돌아간 후 루프 지속
  • break와 마찬가지로 중첩 루프에서는 continue n과 같이 숫자 함께 사용하여 원하는 루프로 이동 가능

shift 문

  • 스크립트의 인수로 입력 받은 파라미터 목록들이 좌측으로 이동
  • shift n 과 같이 숫자를 함께 사용하면 그 숫자만큼 좌측으로 이동
  • 이동한 파라미터는 영구적으로 삭제

exit 문

  • 스크립트를 종료하기 위해 사용
  • 보통 exit은 특정 코드 블록에서 종료해야 하거나 혹은 특정 종료 코드를 반환하여 확인하고 싶을 때 사용

here document

  • I/O 리다이렉션의 특별한 형태
  • ftp, telnet, ex처럼 사용자와 입력을 주고 받는 프로그램에게 명령어 스크립트를 입력시키는데 사용
  • 문서의 시작과 끝을 알리는 키워드를 지정 -> 받아들일 데이터의 범위를 표시하는 기능
  • 보통 EOF 많이 사용하지만
  • 시작 키워드 == 종료 키워드 이기만 하면 상관 X
  • 탭을 제거하기 위해서는 «- 사용 (« 연산자는 탭을 그대로 출력)

산술 연산, 논리 연산

eval 문

  • 목록에 들어 있는 인자들을 결합한 후 평가해서 결과 값을 취함
  • 문자열들을 조합하여 변수에 할당하는데 사용 가능
  • 인자들을 명령어로 변환해서 스크립트 안에서 코드를 만들어 낼 때 유용

역따옴표 혹은 명령어 치환

  • 명령어의 출력을 결과로 리턴, 변수에 할당 가능
  • 명령어 치환의 전형적인 형태는 역따옴표를 쓰는 것 (`…`)
  • $(…) 형식으로도 사용 가능
  • 명령어를 수행 후 출력되는 결과를 스크립트 내부에서 활용하기 위해 많이 사용

산술 연산

  • 표현식을 평가하고 그 결과값을 표준 출력으로 내보냄
  • expr을 이용하거나 (()) 혹은 let을 사용하는 방법

declare로 선언하는 방법

  • bash에서 declare -i 로 이용 명시적으로 변수를 정수형으로 지정할 수 있다
  • 변수를 명시적으로 지정하게 되면 해당 변수에는 “0” 할당
  • 해당 변수로 산술 연산을 하기 위해서는 앞뒤 공백 없이 연산자 사용
  • 변수 타입이 정수형이기 때문에 실수를 지정하게 되면 에러
  • 스트링 지정시 0이 된다

함수

서브루틴으로, 어떤 동작들이 구현된 코드 블록 반복적으로 사용되는 기능들을 하나의 함수로 정의하면 효율적으로 스크립트 작성 가능 시간 절약, 반복되는 코드 최소화, 유지보수 용이

function 키워드를 사용할 수도 있고,. 시용하지 않아도 정의 가능

  • 함수 사용 전 반드시 정의는 되어 있어야
  • 사용자의 입력 혹은 명령어를 다음과 같은 분기로 처리
      1. alias 된 명령인지 확ㅇ니
      1. 정의된 함수인지 확인
      1. 내장 명령인지 확인
      1. 실행 프로그램인지 확인
  • 함수 내부에서 exit 만나면 스크립트 종료
  • 함수의 return 값을 얻어낼 수 있다
  • 자기 자신을 호출하는 재귀 호출도 가능하다

함수 파라미터

함수를 호출할 때 함수로 넘어가는 인자를 의미 인자 순서대로 $1, $2, $3… 으로 변수에 저장되고, $@는 모든 인자 집합을 나타내는 특수 변수

함수 리턴

  • 리턴을 위해 return 키워드를 사용해도 되고, echo 사용해도 된다
  • return 키워드 사용할 때에는 숫자 사용
  • 일반적인 스트링 반환하기 위해서는 echo 사용

source 명령어

  • 일반적으로 환경 설정 파일을 현재 쉘 환경으로 불러올 때 사용
  • 스크립트 내의 source는 다른 위치에 정의된 변수를 스크립트 내부에서 사용하고 싶을 경우 사용
  • 명시적으로 source를 사용하거나 마침표를 사용해도 동일

getopts 명령어

  • 인자를 쉽게 추출하기 위해 getopts 명령어 사용 (getopts는 내장 명령어)
  • $OPTARG 변수에는 getopts로 처리된 인자의 값 저장
  • $OPTIND는 인자 개수를 파악할 때 사용
  • 쉘 스크립트 이름도 0번째 인자 1개로 계산
  • $OPTIND - 1 = 실제 인자의 개수

getopts 옵션 유형

  • -o 옵션 : short type의 옵션 지정
  • -u 옵션 : 전달되는 옵션을 따옴표로 둘러싸지 않도록 한다
  • -l 옵션 : – 형식의 long type 옵션을 지정한다

시그널과 트랩

trap 명령어

  • 스크립트로 시그널이 도달했을 때 어떠한 행동을 취해야 할지를 제어할 수 있도록 한다.
  • trap “명령어; 명령어; …” 시그널 번호
  • trap “명령어; 명령어; …” 시그널 이름

시그널을 가로채서 다른 방법으로 사용하고 싶을때 trap 명령어 사용

정규 표현식

  • 문자나 문자열을 Find and Replace 하는데 사용
  • UNIX의 텍스트 처리 유틸리티인 ed (sed 포함), vi와 같은 편집기, grep 등에서 사용

정규 표현식의 사용

  • 텍스트를 좌에서 우로 검사하면서 여러 규칙과 일치될 문자의 수량을 다양히 시도
    • 대용량의 로그를 배치로 읽어 로그의 처음부터 끝까지 정규 표현식을 통해 패턴 매칭으로 처리
  • 단순 문자열 매핑을 통한 검색 또는 검색 - 치환에 비해 표현할 수 있는 범위 방대
  • 정규 표현식 그 자체만으로는 파싱에는 부적절하다
  • 실시간 매칭 후 액션을 취해야 하는 작업에서는 단순 매핑을 통한 액션에 비해 처리 성능이 떨어짐
  • 실시간 로그 감시, 실시간 침입 탐지, 실시간 패킷 검사 등에 사용

패턴을 일치시킨다는 것이고, 일치의 기본 단위는 문자열

정규 표현식 Constructor

Boolean “or”

  • 2개 이상의 패턴은 | 로 구분
    • apple과 orange 둘 다 찾으려면 apple | orange 라고 적음

Grouping

  • 그룹핑을 통해 패턴 단순화 가능, 괄호 ()나 {}로 표현
    • irteam과 ibteam을 매칭하려면 i(r|b)team으로 표현

Qualification

  • 반복되는 문자 또는 문자열을 치환
  • 물음표 (?) : 하나도 일치하지 않거나 하나만 일치하는 경우
    • colou?r -> “color”, “colour”
  • 별표 (*) : 하나도 일치하지 않거나 하나 이상 일치하는 경우
    • ab*c -> “ac”, “abc”, “abbc”
  • 더하기 (+) : 반드시 하나 이상 일치하는 경우
    • ab+c -> “abc”, “abbc”, “abbbc”

Find and replace

vi나 sed 등에서는 s 명령을 스게 되는데, 이럴 때 패턴과 s 명령, 치환할 문자열 구분 위해 ‘/’ 사용

  • 예 1) s/regexp/replacement : regexp를 찾으면 replacement로 치환하라는 의미
  • 예 2) 45, 100/regexp/p : sed 등에서 45번째 줄에서 100번째 줄 사이에 regexp가 나오면 모두 화면에 출력

유니코드 지원

  • ASCII 1바이트 기준으로 구현됨
  • 현재 대부분의 운영체제와 정규 표현식 라이브러리 및 엔진 체제는 유니코드를 지원하는 추세

한글과 정규 표현식

  • 2000년 중후반까지만 해도 정규 표현식 엔진이 완벽하지 않았으나 현재는 사용 시 큰 지장 X
  • 중요한 것은 시스템 내 컨텐츠의 locale이 정확하게 설정되어 있어야 함 - UTF8이 오동작 방지에 유리

awk

  • 프로그램을 만든 Alfred Aho, Peter Weinberger, Brian Kerningham의 앞글자 따와 awk
  • 정규 표현식으로 원하는 패턴을 추출하기 위한 것이 주목적
  • 파일이나 명령어 (파이프)로부터 입력을 할 수 있다
  • 리눅스에서 awk는 GNU 버전의 gawk로 심볼릭 링크 되어 있음
  • 파일 혹은 파이프 통해 입력 받고 $0이라는 내부 변수에 라인 추라 (개행 문자 단위 구분)
  • 별도의 구분자 없다면 공백 기준으로 필드 구분
  • awk pattern [action]
    • awk -f prog-file file..
옵션 내용
-F FS (구분자) 지정
-f awk 명령어를 파일로 저장한 후 실행 / 처리할 때 사용
변수 내용
NF Number of fields - 레코드 수
NR Number of records - 레코드 번호
OFS Output field seperator - 출력에 대한 필드 구분자
FS Field seperator - 필드 구분자

awk pattern {action} 중 pattern에 위치할 형식은 아래와 같다

패턴 내용
BEGIN awk 본문 시작되기 전에 실행되는 영역
END awk 본문이 끝난 후에 실행되는 영역
pattern1, pattern2 pattern1을 찾은 후 그 후 pattern2가 오는 라인까지 범위 지정
/string/ 슬래시 (/) 안에 있는 문자와 일치하는지 확인

sed

텍스트 처리 위한 stream editor 줄 단위로 입력 받아 룰에 의해 처리한 후 결과 값을 표준 출력이나 파일로 출력

쉘 변수 확장자

문자열을 앞뒤로 자르기 위한 변수 확장자 존재 %는 변수의 뒷부분부터, #은 변수 앞부분부터 잘라낸다

expr을 이용한 정규 표현식

  • 산술 연사자인 expr을 사용해서도 간단한 정규 표현식과 조건식 사용 간으
  • 구분자 “:“를 사용, 뒤에 기술되는 정규 표현식과 매칭되는 문자열 숫자 반환