리눅스 환경에서 사용하는 명령어가 너무 단순하고 쓰던것만 쓴다는 생각에 책 한권을 간단하게라도 훑어 봐야겠다는 생각에 선택한 책
생각보다 내용이 훨씬 더 알차다 (그만큼 내가 허접하니깐.... 후후..)
추석 연휴때 회사의 이중화 작업으로!!!! 고향인 대구에 내려가지도 못해서 각잡고 다 읽고 정리를 하였다.
아래 내용은 책의 내용을 주제별로 정리한 것이지만, 전체 이해를 위해서는 책을 사서 재밌게 읽어보는게 10000배 도움된다.
혹시나 리눅스 개발환경의 입문자라면 이책과 함께 한상곤님의 영상을 같이 보는것을 추천한다
All about dev. on Ubuntu by 한상곤
목차에서 원하는걸 바로 읽어보는것도 좋지만, 순차적으로 읽는것이 더 효과적이다.
앞의 내용과 이어지는 부분이 꽤 많다.
- 만화로 배우는 리눅스 시스템 관리 - Prio 지음 / 서수환 옮김 (Yes24)
- 1화 다른 컴퓨터를 리모트로 조작하고 싶어 (ssh)
- 2화 임시로 관리자 권한을 얻고 싶어 (sudo)
- 3화 다양한 문자열을 한 번에 검색하고 싶어 (grep)
- 4화 터미널에서도 대화형으로 파일을 편집하고 싶어 (vim)
- 5화 vim에서도 복사 & 붙이기 & 되돌리기를 하고 싶어 (yank)
- 6화 갑작스러운 네트워크 끊김에서 복귀하고 싶어 (가상터미널 : tmux)
- 7화 다른 화면도 보면서 작업하고 싶어 (화면 분할)
- 8화 최근 실행한 명령어를 호출하고 싶어 (명령어 이력)
- 9화 명령어 이력 검색
- 10화 네트워크를 건너 파일 복사 (scp)
- 11화 시스템 부하를 파악하고 싶어 (top)
- 12화 시스템 메모리 부족을 파악하고 싶어 (top 표시 전환)
- 13화 로그 파일에서 필요한 줄만 뽑고 싶어 (파이프라인 |)
- 14화 작업 절차를 자동화하고 싶어 (쉘 스크립트)
- 15화 같은 문자열을 스크립트에서 재사용하고 싶어 (쉘 변수)
- 16화 작업 환경과 상태를 정해서 스크립트를 실행하고 싶어 (환경 변수)
- 17화 로그 파일에서 필요한 줄만 뽑고 싶어 (cut)
- 18화 같은 내용의 줄을 세어보고 싶어 (sort와 uniq)
- 19화 CSV 파일을 열의 내용에 따라 정렬하고 싶어 (sort와 >)
- 20화 명령줄 지정으로 작업 내용을 바꾸고 싶어 (명령줄 인수)
- 21화 조건에 따라 처리 흐름을 바꾸고 싶어 (if)
- 22화 명령어 이상 종료에 대응하고 싶어 ($?)
- 23화 같은 처리를 반복해서 실행하고 싶어 (for)
- 24화 공통 처리를 계속 재사용하고 싶어 (쉘 함수)
- 총평
1화 다른 컴퓨터를 리모트로 조작하고 싶어 (ssh)
- Secure Shell의 약자
- 다른 PC에 네트워크를 경유해서 로그인하여 자기 PC처럼 사용하게 해줌
- 접속 방법은
ssh 계정@네트워크명 or IP
- 예제코드 :
ssh jojoldu@192.168.11.5
2화 임시로 관리자 권한을 얻고 싶어 (sudo)
- root 로그인을 막되, 일반 관리자로 활동하기 위한 방법
- 미리 지정한 비밀번호가 있다면 관리자와 동등한 권한으로 명령어 실행 가능
sudo 실제로 사용할 명령어
로 관리자 권한으로 실행 가능
3화 다양한 문자열을 한 번에 검색하고 싶어 (grep)
파일 내용을 빠짐 없이 확인해서 찾는 문자열이 포함되었는지를 조사해주는 명령어
grep이란 Grobal Regular Expression Print
- 사용법 :
grep "검색하고 싶은 문자열" 찾을 파일이 있는 디렉토리 경로
- 보통은 정규표현식과 함께 사용한다.
- "jojoldu" 라는 문자열이 포함된 파일을 /data/log에서 찾아보자.
# -r은 서브폴더까지 검색하는 옵션이다
grep -r "jojoldu" /data/log
4화 터미널에서도 대화형으로 파일을 편집하고 싶어 (vim)
명령줄용 텍스트 에디터
vim
으로 실행이 안되면 설치가 안된 경우이니sudo apt-get install vim
혹은yum install vim
으로 설치하자.- 이 책 내용으로 vim에 대한 전부를 담을순 없다. Vim with Windows by 한상곤을 꼭꼭 참고하자.
- 마우스가 없던 시절에 사용하기위해 탄생했기 때문에 Mode(모드) 라는 개념이 생김
- 동일한 키가 Mode에 따라 다른 행동을 한다.
- 주요 Key ()
- 노멀모드 전환 : 각 모드에서
esc
키 누르면 전환. 일반적으로 홈 화면 역할 - 끼워넣기 모드 전환 (insert) : 노멀모드에서
i
를 누르면 전환, 일반 데이터와 같은 모드 - 편집 저장 : 편집 -> 노멀모드로 전환 ->
:wq
입력 - 검색 : 노멀모드에서
/검색하고싶은 문자열
입력, 다음 단어를 찾고 싶다면n
입력
- 노멀모드 전환 : 각 모드에서
5화 vim에서도 복사 & 붙이기 & 되돌리기를 하고 싶어 (yank)
Vim에서 사용하는 클립보드
복사 붙여넣기
- 복사모드 전환 : 노멀모드에서
v
입력 비주얼 모드에서 화살표 키로 영역 선택
클립보드로 복사 :
y
입력붙여넣기 :
shift+p
입력
- 복사모드 전환 : 노멀모드에서
되돌리기 : 노멀모드에서
u
입력- 앞으로 되돌리기 : 노멀모드에서
shift+u
입력
6화 갑작스러운 네트워크 끊김에서 복귀하고 싶어 (가상터미널 : tmux)
- 사용자 PC와 반대편 서버 사이의 중간 연결자 역할을 한다.
- PC에서의 키 입력을 tmux에서 받아 서버로 전달 하는 방식으로 이해
일반적으로 ssh를 통해 vim을 사용하다가 갑자기 커넥션이 끊어질 경우가 발생하면 작업중이던 vim도 강제 종료가 되는데 이를 방지하기 위해 사용
- tmux, screen, byobu등이 있지만 여기선 tmux를 소개
- 좀 더 자세히 알고 싶은 분들은 여기 참고
설치 :
sudo apt-get install tmux
- 실행 : ssh 접속후 바로
tmux
입력 - 이어서하기 : ssh 접속후 바로
tmux attach
입력- 이렇게 할 경우 이전에 tmux모드에서 사용중이던 내용이 이어진다.
- 빠져나오기 : 서버에 배치 처리 혹은 긴 시간이 필요한 작업을 걸어놓고 tmux 빠져나오기
ctrl+b
입력 ->d
입력- d는 Detach를 나타냄
- vim의 모드전환을
esc
로 하듯이 tmux에서는ctrl+b
입력 후 다음 입력으로 행동 지정- tmux 새탭 열기 :
ctrl+b
입력 ->c
입력 - tmux 다음탭 이동 :
ctrl+b
입력 ->n
입력 - tmux 이전탭 이동 :
ctrl+b
입력 ->p
입력
- tmux 새탭 열기 :
7화 다른 화면도 보면서 작업하고 싶어 (화면 분할)
개인 리눅스 PC에서는 터미네이터 를 사용하면 되지만, tmux로 서버환경에서 작업할 경우 이렇게 할 수가 없다.
이런 상황에서 화면 분할을 위해 사용할 수 있는 명령어
(선배 개발자 분들의 모니터에서 보던 그 화면을 우리도 만들어 보자)
- 자주 사용하는 키
- 가로 분할 :
ctrl+b
입력 ->"
입력 - 세로 분할 :
ctrl+b
입력 ->%
입력 - 분할된 화면간 이동 :
ctrl+b
입력 ->화살표 키
입력 (현재 포커스 된 화면을 기준으로 포커스가 이동) - tmux내에서 스크롤 :
ctrl+b
입력 ->[
입력 ->마우스 휠 or 화살표 키
입력 - 분할 해제 :
exit
입력
- 가로 분할 :
8화 최근 실행한 명령어를 호출하고 싶어 (명령어 이력)
쉘에서 이전에 입력한 명령어들을 볼 수 있는 방법
- 기본적인 사용 : `
위or아래 화살표
입력 명령어
- 이전 검색 :
ctrl+r
입력 ->찾고 싶은 명령어
입력 - 이후 검색 :
ctrl+s
입력 ->찾고 싶은 명령어
입력
- 이전 검색 :
이후 검색의 경우 bash에서 사용할 경우 추가 설정이 필요하다
- bash 설정파일 open :
vim ~/.bashrc
- 설정파일 마지막 위치로 이동 :
shift+g
입력 - 설정 추가 : 마지막 줄에
stty stop undef
추가 - 설정 적용 :
source ~/.bashrc
- bash 설정파일 open :
9화 명령어 이력 검색
- 명력어 이력 저장 갯수 수정
설정파일 열기 : vim ~/.bashrc
파일끝으로 이동 : shift + g
설정 추가
export HISTSIZE 1000
export HISTFILESIZE=10000
저장 및 반영
source ~/.bashrc
- 터미널마다의 명령 히스토리 공유
설정파일 열기 : vim ~/.bashrc
파일끝으로 이동 : shift + g
설정 추가
function share_history {
history -a
history -c
history -r
}
PROMPT_COMMAND='share_history'
shopt -u histappend
10화 네트워크를 건너 파일 복사 (scp)
- 현재 PC의 파일을 반대편 PC로 보내는 경우 : 이쪽에 있는걸 저쪽으로 보낸다는 개념
scp 파일명 사용자계정@반대편 PC(네트워크명 또는 IP):복사될 디렉토리 위치
ex) scp ./file.txt jojoldu@192.168.1.10:/tmp/
- 반대편 PC의 파일을 현재 PC로 가져올 경우 : 저쪽에 있는걸 이쪽으로 가져온다는 개념
scp 사용자계정@반대편 PC(네트워크명 또는 IP):복사할 파일의 위치 현재PC경로(복사될 위치)
ex) scp jojoldu@192.168.1.10:/tmp/file.txt /data/
- 여러개 동시 복사
1. 와일드카드 사용 (/tmp/ 디렉토리에서 .txt로 끝나는 파일 모두)
ex) scp jojoldu@192.168.1.10:/tmp/*.txt /data/
2. 디렉토리 전체 복사(/tmp/ 디렉토리 전체 복사)
ex) scp -r jojoldu@192.168.1.10:/tmp/ /data/
- 다른 PC에서 다른 PC로 파일 복사
scp 사용자계정@반대편1:복사파일위치 사용자계정@반대편2:도착디렉토리
ex) scp jojoldu@192.168.1.10:/tmp/file.txt jojoldu@192.168.1.11:/data/
11화 시스템 부하를 파악하고 싶어 (top)
시스템 부하 관련 정보를 수초 간격으로 실시간으로 갱신파면서 표기해주는 명령어
보고 싶은 서버에 접속해서 top만 입력하면 됨
아래는 top 명령어로 출력되는 화면에서 확인해야할 내용들이다.
load average
- CPU가 처리하는 걸 기다리는 작업 개수
- CPU는 한 번에 하나밖에 처리 못하니, 그동안 발생한 새로운 작업은 쌓아둔다.
- load average는 1분당 평균으로 몇 개의 일이 쌓이는지를 나타냄
- 코어의 수에 따라 load average 부하정도를 판단해야 한다. (load average >= cpu 코어수 : 과부하 상태)
- 쿼드코어는 CPU가 4개이므로, 한 번에 4개의 일을 처리하니 load average는 4이하가 안전한 상태이다.
%CPU / TIME+
- %CPU 란 해당 프로세스사 차지하는 CPU 사용율이다.
- TIME+ 란 실제로 CPU를 사용한 시간이다.
- %CPU가 높아도 TIME+가 짧은 경우 해당 프로세스를 수행하는 시간이 짧고 휴식시간이 긴 형태이므로 실제 부하량은 낮다고 볼 수 있다.
- 즉, 과부하 원인을 찾을때는 CPU사용율이 높은지/CPU사용시간이 긴지로 확인해야 한다.
COMMAND
- 프로세스를 실행했을 때 실행한 명령어를 표시
- 해당 프로세스를 정말 멈춰도 되는지 확인을 위해 주로 본다.
- top이 켜져있는 상태로 COMMAND의 약자인 "c"를 입력할 경우 상세 커맨드가 표시된다.
12화 시스템 메모리 부족을 파악하고 싶어 (top 표시 전환)
CPU 부하량이 낮아도 load average가 높은 경우가 있는데, 대표적인 예가 디스크 I/O이다.
하드디스크에 저장한 파일을 찾거나, 내용을 읽거나, 파일 저장이 끝날때까지 등등의 경우가 있다.
Swap
- 스왑 발생량
- CPU는 메모리에서 작업을 진행하는데, 메모리 여유 공간이 부족하면 새로운 작업을 할 수 없다 (즉, 작업들이 대기시간에 빠진다.)
- 스왑아웃 : OS에서 메모리 공간 확보를 위해 최근에 사용하지 않은 데이터를 하드디스크로 옮기는 행위
- 스왑인 : 스왑아웃한 데이터가 필요해지면 하드디스크에서 메모리로 데이터를 되돌리는 행위
- 스왑아웃 & 스왑인을 합쳐 스왑이라고 한다.
- 메모리 사용량이 늘면 늘수록 스왑이 빈번하게 발생해서 I/O 대기시간이 길어지며 load average가 높아지게 된다.
- Swap가 높으면 스왑 발생량이 높아 load average가 높다는 이야기이다.
- top의 정렬순서를 변경하고 싶을 경우
- cpu 시간 순 : shift + t
- cpu 사용량 순 : shift + p
%MEM
- 프로세스가 소비하는 메모리양
- 전체 메모리 중 해당 프로세스가 몇 %의 메모리를 차지하는지 표시해준다.
- top의 기본정렬은 CPU부하가 높은 순이라 메모리가 높은 순으로 정렬하고 싶을 경우 shift+m을 누르면 된다.
13화 로그 파일에서 필요한 줄만 뽑고 싶어 (파이프라인 |)
명령어의 실행 결과 출력을 그대로 다른 명령어에 넘겨주는 것 (shift+\ 눌렀을 때 나오는 | 를 말함)
보통은 grep와 함께 사용해서 로그파일에서 여러 조건을 사용한 조회시에 사용한다.
(동시에 여러 파이프라인을 사용한 경우 대략 이런 느낌?)
출력을 넘기는 명령어 | 출력을 받을 명령어 | 출력을 받을 명령어 | 출력을 받을 명령어
ex) grep 'NullPointerException' /data/log/logback/20160914.log | less
zcat
- 압축 파일을 읽어서 내용을 풀어서 출력하는 명령어
- 압축된 log파일을 읽을 때 자주 사용
- 비슷한 형식으로 zxcat(.xz 압축파일), unzip(zip 압축파일)
실시간으로 조건 조회
- tail : 파일 내용의 끝부분만 출력
- -f : 내용이 추가될때마다 그 부분을 실시간으로 출력
tail -f 조회조건
ex) tail -f /data/log/logback/20160914.log | grep 'NullPointerException' | grep 'Member'
14화 작업 절차를 자동화하고 싶어 (쉘 스크립트)
쉘 작업을 자동화하도록 만든 각본 같은 것
- 실제로는 명령어 실행 절차를 작성하면 이를 그대로 실행시켜준다.
- 파이프라인이 명령어를 옆으로 연결한거라면, 쉘 스크립트는 명령어를 세로로 연결한 것
작성예)
#!/bin/bash
명령어1
명령어2
- 제일 첫줄의
#!/bin/bash
는 bash로 아래 명령어들을 실행시키겠다는 의미이다. - 보통 작성된 쉘 스크립트는 실행 권한이 없으므로 아래처럼 실행권한을 주어야 한다.
chmod +x setup.sh
- 명령어 실행 도중 실패가 발생할 경우 다음 명령어부터 에러가 계속 발생할 수 있다.
- 이럴 경우 에러가 발생하면 그자리에서 바로 실행을 종료 시키는 코드를 추가하면 된다.
- 굳이 모든 명령어 라인에 추가할 필요는 없다 (예를 들어 폴더이동 같은경우)
- 다만, 실패했을 때 그 뒤 처리에 영향이 가는 명령어가 있다면 그다음 줄에 무조건 넣는것이 좋다.
작성 예)
#!/bin/bash
명령어1
if [ $? != 0 ]; then exit; fi
명령어2
15화 같은 문자열을 스크립트에서 재사용하고 싶어 (쉘 변수)
일반적으로 우리가 알고 있는 프로그래밍언어의 변수와 동일한 역할을 한다.
반복적으로 사용하는 값일 경우 변수를 선언 및 할당하여 해당 변수를 사용함으로써 수정이 용이해진다.
- 기본적인 사용법은
변수명=명령어 혹은 값
- 해당 변수를 사용하고 싶은 경우엔
$변수명
을 사용하면 된다.
- 해당 변수를 사용하고 싶은 경우엔
#!/bin/bash
LOG=/data/log/logback/20160914.log
cat $LOG | grep 'NullPointerException'
- 옵션 조합 역시 변수로 할당 할 수 있다.
- 예를 들어 압축하기/풀기 옵션도 가능하다.
#!/bin/bash
TAR_EXTRACT="tar xfv"
TAR_COMPRESS="tar cfv"
#eval을 사용하면 문자열을 명령어처럼 사용가능하다 (Javascript의 eval과 비슷)
eval "$TAR_EXTRACT file.tar.gz"
eval "$TAR_COMPRESS directory"
- 디렉토리 경로에 변수를 지정할 수도 있다.
#!/bin/bash
BASE=/data/log/logback
# $BASE로 써도 되고, ${BASE} 로 써도 되는데 가독성을 위해 ${} 선호
LATEST=${BASE}/access.log
PREV=${BASE}/access.log.7.gz
16화 작업 환경과 상태를 정해서 스크립트를 실행하고 싶어 (환경 변수)
작업하는 서버에 따라 관리용 사용자 이름이 다를 경우 실행하는 명령어 내용에 사용자명이 추가되어 스크립트 그대로 사용할 수는 없다.
이럴 경우 사용할 수 있는 것이 환경 변수이다.
HOME
- 환경 변수중 HOME은 해당 사용자의 홈 디렉토리 경로가 된다.
- 예를 들어
mkdir ${HOME}/result
라고 지정을 하면 jojoldu 사용자의 서버에서는/home/jojoldu/result
디렉토리가 생성되고, jojoldu2사용자의 서버에서는/home/jojoldu2/result
디렉토리가 생성된다.
env
- 환경 변수 목록
자주 사용하는 환경 변수들
- PWD : 현재 디렉토리 경로
- EDITOR : 정해진 텍스트 에디터 (vim, Emacs, nano 등) 의 경로
- PAGER : 정해진 페이저 (less 등)의 경로
- USER : 현재 사용자의 사용자명
- GROUP : 현재 사용자의 그룹명
- HOSTNAME : 머신의 호스트명
- 굳이 vim이나 less를 직접 지정하지 않는 이유는 각 사용자마다 사용하는 어플리케이션이 다르기 때문
명령어 치환
- result.txt가 매일 생성되며, 이를 날짜별로 파일명을 변경하고 싶을 경우
mv result.txt result-$(date +%Y-%m-%d),txt
로 스크립트를 작성하면 스크립트 실행시마다 오늘의 날짜로 result-yyyy-MM-dd.txt 형식으로 생성된다.- date : 오늘의 날짜
- %Y : yyyy형식 (yy를 원할 경우 %y)
- %m : MM형식 (01 ~ 12)
- %d : dd 형식 (01 ~31)
- %H : hh 형식 (00 ~ 23)
$(명령어) vs '명령어'
- '명령어 '명령어'' 라는 식으로 중첩 명령어 사용시 가독성이 떨어지므로 $(명령어) 사용법 권장
- 예전에는 '명령어' 밖에 사용하지 못해 호환성문제로 아직 사용하는 경우가 있음
17화 로그 파일에서 필요한 줄만 뽑고 싶어 (cut)
- 파이프라인으로 넘어온 내용의 각줄마다 필요한 부분만 잘라내서 넘겨주는 명령어
- 구분자를 이용해 필요한 정보를 구분한다 대표적으로 log 파일에서 스페이스를 구분자로 사용해서 추출하는 경우가 있다.
- 사용법
- 구분자 지정 :
-d "구분자"
- 추출할 위치 :
-f 추출할위치
(구분자로 파싱뒤 몇번째 위치인지)
- 구분자 지정 :
- 예를 들어 다음과 같은 Apache(아파치) 로그에서 url 경로를 추출하려면 어떻게 해야할까?
192.168.11.3 - - [12/Feb/2016:15:24:57 +0900] "GET /getUserInfo HTTP/1.1" 200 13472 "-" "Mozilla/5.0 (Windows NT 6.0; rv:17.0) Gecko/20100101 Firefox/17.0"
cut -d " " -f 7
로 하면 스페이스(" ")로 파싱후 7번째 위치인/getUserInfo
를 추출해낼 수 있다.- 만약 구분자가 쌍따옴표(")인 경우엔 홀따옴표로 감싸면 된다 ->
cut -d '"' -f 6
18화 같은 내용의 줄을 세어보고 싶어 (sort와 uniq)
- sort : 내용을 알파벳순으로 재정렬 하는 명령어
uniq : 이어진 중복을 제거 한다
- 즉, 연속되지 않은 경우 중복제거 되지 않는다. 이를 위해 sort를 함께 쓰는 경우가 대부분이다.
-c
옵션을 같이 사용할 경우 중복제거 횟수 확인이 가능하다 (c : count)
access log에서 같은 url 호출 횟수를 알고 싶을때?
cat /data/log/nginx/access.log | cut -d " " -f 7 | sort | uniq -c | less
로 하면중복횟수 url
로 출력된다.
중복횟수 순으로 내림차순 하고 싶을 경우 해당 결과를 다시 파이프라인으로 받아 sort -r (역 정렬) 하면 된다.
cat /data/log/nginx/access.log | cut -d " " -f 7 | sort | uniq -c | sort -r| less
조회수가 가장 많은 5개, 가장 적은 5개 url들만 보고 싶다면?
- head : 파이프라인을 통해 넘어온 데이터의 앞부분 10개를 추출하는 명령어
- tail : 파이프라인을 통해 넘어온 데이터의 뒷부분 10개를 추출하는 명령어
- 개수 조절을 원한다면
-n 갯수
옵션을 추가하면 된다. - 가장 많은 5개 :
cat /data/log/nginx/access.log | cut -d " " -f 7 | sort | uniq -c | sort -r| head -n 5 |less
- 가장 적은 5개 :
cat /data/log/nginx/access.log | cut -d " " -f 7 | sort | uniq -c | sort -r| tail -n 5 |less
19화 CSV 파일을 열의 내용에 따라 정렬하고 싶어 (sort와 >)
예를 들어 csv 파일에서 필요없는 비고는 삭제하고, 재고수로 재정렬 해야 한다면?
작업 순서
- 불필요한 열 제거
- 줄을 재고수 크기로 재정렬
- 결과를 파일로 출력하기
불필요한 열 제거
- cut을 활용
- 1~3 열까지는 사용해야하며, 4열부터는 필요 없다.
- cut의
-f
옵션은 뒤에 하나의 숫자만 올수도 있지만, 여러숫자/범위지정 등의 옵션도 가능하다. - 여러숫자 :
-f 1,3,4,6
- 범위지정 :
-f 1-3
- 1~3열까지만 추출 :
cat items.csv | cut -d "," -f 1-3
재고수 크기로 재정렬
- sort도 cut처럼 구분자로 나누는 기능이 존재
- 구분자 지정 :
-t "구분자"
- 열 지정 :
-k 3
- 일반적으로 정렬기준시 문자열비교로 앞에서부터 하나씩 비교하기 때문에 숫자의 경우 의도와 다르게 정렬된다. (20, 3이 있을 경우 3이 먼저 된다.)
- 숫자기준으로 정렬 :
-n
- 재고수 크기로 재정렬 :
sort -t "," -k 3 -n
- 앞의 내용과 이어가면 :
cat items.csv | cut -d "," -f 1-3 | sort -t "," -k 3 -n | less
결과를 파일로 출력하기
>
(리다이렉트) : 명령어 실행 결과를 저장하는 명령어>
의 경우 이미 있는 파일은 지우고 새로운 파일 생성>>
의 경우 기존 파일에 내용 추가- 앞의 내용과 이어가면 :
cat items.csv | cut -d "," -f 1-3 | sort -t "," -k 3 -n > /data/result.txt
tab을 구분자로 쓰기
- cut 명령어 실행시에는
-d
를 지정하지 않으면 기본 구분자가 tab으로 지정된다. - 쉘 스크립트내에서는
cut -d "탭문자"
로 쓸수 있다.
- cut 명령어 실행시에는
20화 명령줄 지정으로 작업 내용을 바꾸고 싶어 (명령줄 인수)
명령줄 인수 (명령어 인자값 혹은 인수) : 명령어를 실행시킬때 스페이스 단위로 입력하는 값들을 말한다.
cat /data/log/nginx/access.log
에서/data/log/nginx/access.log
를 말한다.- 명령어 인수1 인수2 인수3 에서 인수1을 쓰고 싶다면 $1을, 인수2를 쓰고 싶다면 $2 를 쓰면 된다.
예제코드 (아래 두 개의 쉘스크립트의 공통요소를 찾아 하나의 쉘 스크립트로 수정해보자)
#!/bin/bash
DIR=/data/csv
SOURCE="${DIR}/items.csv"
echo "$SOURCE 처리중"
cat $SOURCE
echo "$SOURCE 처리완료"
#!/bin/bash
DIR=/data/csv
SOURCE="${DIR}/person.csv"
echo "$SOURCE 처리중"
cat $SOURCE
echo "$SOURCE 처리완료"
- 결국 사용하는 csv 파일명만 다르지 하는 일은 같다. 이럴 경우 csv 파일명을 인수로 받도록 하면 하나의 쉘스크립트로 가능하다.
- 수정본 (파일명 : ./show.sh)
#!/bin/bash
DIR=/data/csv
SOURCE="${DIR}/$1"
echo "$SOURCE 처리중"
cat $SOURCE
echo "$SOURCE 처리완료"
- 첫번째 인수를 파일명에 쓰도록 하였다 (
$1
) 사용법 :
./show.sh items.sh
혹은./show.sh person.sh
인수 이름 참조
- 사용해야하는 인수가 많아질 경우, 몇번째 인수가 어떤 값을 나타내는지 구분하기가 쉽지 않음.
- 이를 위해 인수 앞에 이름(변수)를 할당해서 해당 변수를 참조하도록 할 수 있다.
예제코드 (./test.sh)
#!/bin/bash
BASE=$1
NEXT=$2
PREV=$3
OUTPUT=$4
- 위 스크립트를 실행시키려면
./test.sh a.log b.log c.log d.log
식으로 실행시켜야 하는데 이럴 경우 각 인수들의 역할을 구분하기 힘들다. - 개선된 코드 (./test.sh)
#!/bin/bash
#b,n,p,o을 옵션으로 사용하겠다는 의미, 추가를 원하면 :옵션명 을 사용하면 된다
while getopts b:n:p:o OPT
do
case $OPT in
#옵션명) 변수명="$OPTARG" ;; 로 사용할 수 있다.
b) BASE="$OPTARG" ;;
n) NEXT="$OPTARG" ;;
p) PREV="$OPTARG" ;;
o) OUTPUT="$OPTARG" ;;
esac
done
- 위와 같이 스크립트를 작성하면 쉘 스크립트 실행시
./test.sh -b a.log -n b.log -p c.log -o d.log
로 사용 할 수 있다. - 이렇게 되면 a.log가 BASE의 역할을 하고, b.log가 -n의 역할을 하는 것을 바로 알수 있어 실수할 여지가 줄어든다.
21화 조건에 따라 처리 흐름을 바꾸고 싶어 (if)
쉘 스크립트에서 조건에 따라 실행을 다르게 하고 싶을 경우 사용
- 만약 인수가 2개라면 Hello를 출력하고, 아니면 "Bye"를 출력
#!/bin/bash
#$#은 스크립트에 지정한 인수개수를 의미함 즉, 들어온 인수가 2개라면 이란 조건
if[ $# = 2]
then
echo "Hello!"
else
echo "Bye!"
fi
if[ $# = 2]
처럼 space가 계속 들어간 이유는[
도 명령어라서 그렇다.- 즉,
$#
,=
,2
모두가[
의 인수로 들어가는 것이다.
22화 명령어 이상 종료에 대응하고 싶어 ($?)
에러가 발생하면 거기서 즉시 종료
$?
는 바로 전에 실행한 명령어의 종료 상태를 나타낸다.- 이를 이용하면 중요 명령어 실행전에 이전 명령어가 정상적으로 실행되었는지 아니었는지 확인후, 실행/종료를 선택할수 있다.
- 간단한 체크 코드
if [ $? != 0 ]; then exit; fi
: 만약 이전 명령어 종료 상태가 0 (정상)이 아니라면 스크립트를 종료 시킨다.
23화 같은 처리를 반복해서 실행하고 싶어 (for)
- 아래와 같이 반복적으로 스크립트를 실행시켜야 하는 경우를 생각해보자.
./create-report.sh a.log
./create-report.sh b.log
./create-report.sh c.log
./create-report.sh d.sh
- 이걸 반복문으로 쉘스크립트를 작성하면
#!/bin/bash
#fileName이란 변수에 a.log~d.log까지를 하나씩 할당하겠다는 의미
for fileName in a.log b.log c.log d.log
do
./create-report.sh $fileName
done
- 좀더 자동화시켜 특정 디렉토리 하위의 모든 .log 파일을 실행시키고 싶다면
#!/bin/bash
#cd /data/log로 이동 후, 나오는 모든 .log를 fileName이란 변수에 할당하겠다는 의미
for fileName in 'cd /data/log; ls *.log'
do
./create-report.sh $fileName
done
24화 공통 처리를 계속 재사용하고 싶어 (쉘 함수)
우리가 흔히 사용하는 언어들의 함수 혹은 메소드와 동일한 기능을 말한다.
- 예제코드 (아래 메세지를 3번 호출하기)
#!/bin/bash
#hello라는 이름을 가진 함수 선언
hello() {
echo "안녕하세요"
echo "jojoldu입니다"
echo "잘 부탁드립니다."
}
#앞에서 선언된 hello함수 3번 호출
hello
hello
hello
- 함수 인수
- 쉘 인수처럼 함수도 인수를 받을 수 있다
- 사용법은 쉘 인수와 동일한데,
함수명 인수1 인수2
로 사용하면 된다.
- 예제코드 (hello 함수에서 인사자의 이름을 인수에 따라 변경하기)
#!/bin/bash
#hello라는 이름을 가진 함수 선언
hello() {
echo "안녕하세요"
# 1번째 인수 할당
echo "$1입니다"
echo "잘 부탁드립니다."
}
#jojoldu, mint, HarmoniKR 로 인사하기
hello jojoldu
hello mint
hello HarmoniKR
- 만약 특정 조건에 따라 함수를 종료시킨다면
exit 1
가 아닌return 1
을 해야한다exit 1
의 경우 함수뿐만 아니라 스크립트까지 종료 시킨다.
#!/bin/bash
report() {
if [ $1 = "" ]
then
echo "인수가 필요함"
return 1
fi
}
- 함수 안에서 $1과 같이 인수사용을 하게 되면 쉘 스크립트의 인수가 아니라 함수의 인수를 사용하게 된다.
- 만약 함수에서 쉘 스크립트의 인수를 사용하고 싶다면 함수 밖에서 변수에 해당 인수를 할당하고 함수에선 변수를 사용하도록 해야한다.
총평
신입 사원이 올 경우 꼭!! 읽어보라고 권유하는게 좋을것 같다
반대로 본인이 리눅스 환경의 신입 개발자라면 꼭! 읽어보길 추천한다.