쉘 스크립트와 cron coearth, george
쉘 스크립트(shell script)란? 쉘의 명령줄들을 모아놓은 것!
쉘이란? 쉘은 운영 체제 상에서 다양한 운영 체제 기능과 서비스를 구현하는 인터페이스를 제공하는 프로 그램이다. 쉘은 사용자와 운영 체제의 내부(커널) 사이의 인터페이스를 감싸는 층이기 때문에 그 러한 이름이 붙었다. –Wikipedia User의 명령어를 해석, 커널에 전달 sh, ash, bash, csh, tcsh, ksh, scsh, zsh, … 다양한 쉘 이 존재
스크립트란? 스크립트 언어(scripting language) 명령어들을 모아놓은 것 최종사용자가 응용프로그램의 동작을 사용자의 요구에 맞게 수행할 수 있도록 해준다. https://ko.wikipedia.org/wiki/%EC%8A%A4%ED%81%AC%EB%A6%BD%ED%8A%B8_%EC%96%B8%EC%96%B4
쉘 스크립트(shell script) 쉘에서 돌아가도록 쓰인 스크립트! 컴파일 단계가 없어 다른 언어로 쓰인 코드보다 빠른 경우가 많다. 다차원배열 불가, linked list같은 ADT선언이 불가능하므로 ADT를 쓰 고 싶다면 C언어나 다른 언어들을 사용하자 단순 sh스크립트는 유닉스, 리눅스, BSD 운영 체제, therof 버전, 시스 템 유틸리티 등과 호환이 잘 되지만 복잡한 쉘 스크립트의 경우 쉘, 유틸리티, 다른 필수 요소간의 차이가 많은 경우 실패할 가능성이 있 습니다. 이식성 문제 http://ora-sysdba.tistory.com/entry/Shell-Script-%EC%99%9C-%EC%89%98-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D%EC%9D%B4-%ED%95%84%EC%9A%94%ED%95%9C%EA%B0%80
이식성 문제 공교롭게도 여러 쉘과 스크립팅 언어들은 POSIX 1003.2 표준으로 움직이고 있는 것처럼 보 입니다. --posix 옵션을 주거나 헤더에 set -o posix 라고 해서 Bash 를 부르면 이 POSIX 표준과 거의 호환이 되게 실행해 줍니다. 이렇게 하지 않더라도 Chet Ramey 가 ksh의 기능을 Bash 최신 버전으로 부지런히 포팅하고 있기 때문에, 거의 대부분의 Bash 스크립트들은 별다른 수정없이 ksh에서 잘 동작하고 반대도 잘 동작할 것입니다. 상업용 유닉스 머신에서 표준 명령어의 GNU 전용 기능들을 사용하게 되면 제대로 동작하 지 않을 수도 있습니다. 하지만 이 문제는 최근 몇 년동안 조금씩 문제가 되질 않고 있는데, "거대"(big-iron) 유닉스에서 쓰이는 특허가 걸린 유틸리티들이 점차 GNU 용으로 바뀌고 있 기 때문입니다. 칼데라에서 최근 내놓고 있는 원래의 많은 유닉스 유틸리티의 소스들은 이 런 경향을 점차 더 가속화 시키고 있습니다. https://wiki.kldp.org/HOWTO/html/Adv-Bash-Scr- HOWTO/portabilityissues.html
Shebang #!: Shebang 모든 script는 shebang 라인으로 시작 script를 어떻게 해석할 것인지 알려줌 #!interpreter [optional-arg] ex) #!/bin/sh : sh를 이용하여 실행하겠다. #!/usr/bin/env python: python을 쓰겠다. shebang 라인은 shell script만을 위한 것이 아닙니다.
명령어(bash) pwd: 현재 경로 표시 echo [str]: str을 출력 file [filename]: filetype을 출력 read var: 입력 값을 변수 var에 대입 exit: 쉘 스크립트를 끝냄 tee [filename]: 표준출력을 file에 쓰기 ex) ls | tee result.txt : 현재 디렉토리의 파일 목록을 result.txt에 저장 cat, date, who, … 이 외에도 grep 처럼 shell에서 쓰이는 패키지들을 사용할 수도 있습 니다.
Hello world출력 다들 해보세요 ~$ vi hello #!/bin/bash echo “hello world!”
Hello world 출력 -bash: ./hello: Permission denied ???????????
Hello world 출력 실행 권한을 줘야 함 ~$ chmod +x hello ~$ ./hello hello world! 혹은 sh hello나 bash hello로 실행 ~$ sh hello hello world! 전 사실 chmod 쓰기 귀찮을 때 sh hello로 실행합니다.
변수 환경변수와 시스템변수(지역변수)로 나뉘어 있 음 export var1=값 으로 선언을 하면 parent shell에 서 생성한 var1이라는 변수를 child shell에서 쓸 수 있음 (역은 성립 안 함.)
export 예시
변수 변수의 선언 변수를 호출할 때는 $를 사용 (없으면 string으로 인식.) 쉘 변수는 타입이 없다. 변수이름=값 =양쪽으로 공백이 있으면 안 됨. 쉘 스크립트에서는 공백의 유무가 아주 중요함. 변수를 호출할 때는 $를 사용 (없으면 string으로 인식.) 단, 변수에 값을 대입할 때는 $을 넣지 않는다. ex) a=1 echo $a 쉘 변수는 타입이 없다.
변수 ~$ vi variable #!/bin/bash a=5 echo a echo $a echo aaaa$aaaaaa ~$ sh variable a 5 aaaa
변수 이 line에서 $aaaaaa가 하나의 변수로 인식되어 빈 string처리가 되었고 aaaa만 출력되었다. echo aaaa$aaaaaa 이 line에서 $aaaaaa가 하나의 변수로 인식되어 빈 string처리가 되었고 aaaa만 출력되었다. string안에서 변수를 선언할 때에는 ${var}를 사용 echo aaaa${a}aaaaa ~$ sh variable a 5 aaaa5aaaaa
변수 변수 입력 read var ~$ vi variable #!/bin/bash echo 변수를 입력하세요 read a echo 변수=$a ~$ sh variable 변수를 입력하세요 5 변수=5
변수 특수 변수 $$: shell 자신의 PID $!: shell이 마지막에 실행한 background proces의 PID $*: 인자 전체의 list $@: 인자 전체의 list, 구분자가 IFS변수의 영향을 받지 않음 $#: 인자의 개수 $0: shell 자신의 file명 $1 ~ $n: shell에 부여된 인자의 값 (인자 번호가 10이상이면 ${10}처럼 중괄호로 묶어주어야 합니다.) $?: 직전 명령의 성공 여부 (성공 0), 에러가 발생했거나 exit으로 빠져나갔을 경우 에러 넘버를 알려줌
$@와 $*의 비교 (IFS : internal field separator) for문은 뒤에 나 올거에요 “1” “2” “3” “4”로 저장됨 $*는 구분자가 IFS의 영향을 받아 변수를 저장할 때 원래 인자를 입력 받은 형태와 다르게 저장될 수 있다.
변수 변수 != 인자 ~$ vi temp.sh ~$ bash temp.sh v1 v2 v3 3 v1 v2 v3 temp.sh #!/bin/bash a=5 echo $# echo $@ echo $* echo $0 echo $1
매개변수 확장 ${parm:-`default`} : parm이 존재하지 않으면 default의 명령으로 대체된다. ex)a=5; echo “a = ${b-`echo $a`}” a = 5 출력 ${#parm} : parm의 길이를 참조한다. ${parm%word} : 끝에서부터 parm을 읽어 word와 일치하는 parm의 최소 부분을 제거하고 나머지를 반환한다. ex)parm=“0abc1abc2abc3”; echo ${parm%a*} 0abc1abc2 출력 ${parm%%word} : 끝에서부터 parm을 읽어 word와 일 치하는 parm의 최대 부분을 제거하고 나머지를 반환한다. ex)parm=“0abc1abc2abc3”; echo ${parm%%a*} 0 출력
매개변수 확장 ${parm#word} : 처음부터 parm을 읽어 word와 일 치하는 parm의 최소 부분을 제거하고 나머지를 반환 한다. ex)parm=“abc1abc2abc3”; echo ${parm%a*} bc1abc2abc3 출력 ${parm##word} : 끝에서부터 parm을 읽어 word와 일치하는 parm의 최대 부분을 제거하고 나머지를 반 환한다. ex)parm=“abc1abc2abc3”; echo ${parm%%a*} 아무것도 출력되지 않음 http://blog.naver.com/PostView.nhn?blogId=jay8099&logNo=70006134512&parentCategoryNo=8&categoryNo=&viewDate=&isShowPopularPosts=false&from=postView http://www.dreamy.pe.kr/zbxe/CodeClip/3765748 참고하세요
정수형 연산 두 가지 방법이 존재 +, -, *, /, % 연산 가능 plus=$(($a+$b)) (띄어쓰기 없음) plus=`expr $a + $b` (주의, 작은따옴표(‘)가 아닌, 키보드의 tab 키 위의 ` 띄어쓰기 있음) +, -, *, /, % 연산 가능 단, expr을 사용할 때에는 곱하기 연산에서 ‘*’혹 은 \*를 써야함.
실수형 연산 expr을 이용해서 실수끼리의 연산을 해봅시다. 아니 실수형 연산이 안되잖아? 쉘 스크립트 완전 구리네
실수형 연산 우리는 쉘 스크립트를 만든 사람이 똑똑하다는 것을 잊으면 안됩니다.
실수형 연산 음 실수형 연산도 지원이 되는구나 잠깐 awk라는게 튀어나왔네? 저건 뭐지?
awk란? awk는 데이터 처리를 위해 최적화되어 있는 프로 그래밍 툴이다. awk는 C형태의 문법을 갖는 필드 단위의 패턴(field-oriented pattern) 처리 언어 https://wiki.kldp.org/HOWTO/html/Adv-Bash-Scr-HOWTO/sedawk.html 여기선 $a가 필드1, $b가 필드2가 되었습니다. awk ‘{printf “%.2f”, $1 * $2}’에서 $1가 필드1, $2가 필드2를 의미합니다.
awk란? awk는 입력된 각 줄을 필드로 나눕니다. 디폴트로 필드는 공백문자를 통해 분리가 됩니 다. 이러한 특징으로 인해 awk는 구조화된 텍스트 파 일이나 테이블 처리에 이상적인 도구가 됩니다 (ex, 성적처리, …)
>, <, >=, <=, ==, != awk의 연산자 연산자 내용 =, +=, -=, *=, /=, %= 배정(assignment)연산자 +, -, *, /, %, ++, -- 산술 연산자 ||, &&, ! 논리 연산자(or, and, not) >, <, >=, <=, ==, != 비교 연산자 이외에도 atan, cos, exp처럼 다양한 수치 연산들과 length, tolower같 은 다양한 문자열 연산들을 제공하며 입출력 관련된 함수도 많이 있 습니다. 사실 awk와 sed만 다뤄도 하나의 세미나가 나올 분량이 될 것 같으니 이쯤에서 awk는 패스하도록 하죠 궁금하신 분들은 구글에 awk를 치면 정말 다양한 자료들을 찾을 수 있으니 참고하세요! awk와 sed를 잘 이용하면 스크립트의 능력이 엄청나게 상승해요 http://www.dreamy.pe.kr/zbxe/CodeClip/6332
비교 연산 산술 비교 연산 산술 비교 연산자 의미 정수 1 –eq 정수 2 두 정수가 같으면 참 아니면 거짓 정수 1 –ne 정수 2 두 정수가 다르면 참 아니면 거짓 정수 1 –gt 정수 2 정수 1이 정수 2보다 크면 참 아니면 거짓 정수 1 –ge 정수 2 정수 1이 정수2보다 크거나 같으면 참 아니면 거짓 정수 1 –lt 정수 2 정수 1이 정수 2보다 작으면 참 아니면 거짓 정수 1 –le 정수 2 정수 1이 정수 2보다 작거나 같으면 참 아니면 거짓
비교 연산 문자열 비교 연산 문자열 비교 연산자 의미 문자열 1 = 문자열 2 두 문자열이 같으면 참 아니면 거짓 문자열 1 != 문자열 2 두 문자열이 다르면 참 아니면 거짓 -n 문자열 문자열이 null이 아니면 참 -z 문자열 문자열이 null이면 참
if문 #!/bin/bash if [ condition ] //condition에는 비교연산과 같은 조건식이 들어감 then commands elif [ condition ] else fi //if문의 종료
case문 #!/bin/bash case $변수 in 1) commands;; //마지막 줄에 ;;을 써주어야 한다 2) *) //예외 처리 commands esac //case문의 종료
&&과 || &&: 앞의 조건식이 참일 때 &&뒤의 문장을 실행 ||: 앞의 조건식이 거짓일 때 ||뒤의 문장을 실행 ~$ vi control.sh #!/bin/bash a=5 b=5 [ $a -eq $b ] && echo a=b [ $a -eq $b ] || echo a!=b ~$ sh control.sh a=b
while문, until문 #!/bin/bash while [ condition ] do commands done until [ condition ] do commands done //condition을 만족할 때 까지
for문 두 가지 방법 가능 #!/bin/bash for 변수 in list do commands done for ((i=0; i<10; i++)) do commands done
for문
간단한 실습 이전 장의 예제를 이용해 본인의 홈 디렉토리 안 에 있는 txt파일의 목록을 list.tmp에 저장하는 쉘 스크립트를 작성해보자 ${parm##word} : 끝에서부터 parm을 읽어 word와 일 치하는 parm의 최대 부분을 제거하고 나머지를 반환한다. 위에 있는 매개변수 확장을 이용하자
간단한 실습 간단하죠?
배열 declare –a arrayname으로 선언 (사실 안 써도 됨) arr=(1 2 3)로 선언 가능, 이때 arr[0]=1, arr[1]=2, arr[2]=3으로 처리 arr2[24]=1; arr2[2] = 2처럼 아무렇게나 index를 잡아 선언할 수도 있음. 단, index는 0이상의 정수로 선언 해야 함 이때 arr2의 길이는 2가 됨 배열의 참조는 ${arr[1]} ${#arr[@]}나 ${#arr[*]}를 이용하여 배열의 길이 구할 수 있음
declare 혹시나 궁금해 하실 분들을 위해 준비했습니다. 이 키워드는 변수의 특성을 제한할 수 있습니다. declare –r var : 읽기 전용 변수 선언(const) declare –i var : 정수 declare –a arr : 배열 declare –f func : 함수 func의 선언을 보여줍니다. 뒤에 인자를 안 넣어주면 모든 선언된 함수 목록을 보 여줍니다. declare –x var : export변수 선언과 같습니다.
함수 #!/bin/bash function func1(){ //function 생략 가능 Commands return var //생략 가능 } func1
함수 #!/bin/bash function var_test(){ //function 생략 가능 local test_var_local=“LOCAL” test_var_global=“GLOBAL” return } var_test echo $test_var_local echo $test_var_global ~$ sh func GLOBAL
함수 #!/bin/bash function add(){ return `expr $1 + $2` } add 5 10 echo $? 함수에 인자를 넣어 줄 수 있고 return 값 역시 받 을 수 있습니다. return 값은 $?안에 저장됩니다.
함수 재귀함수도 구현 가능합니다.
cron
크론이란? Unix-like 운영체제의 작업 스케줄러 cron 설정 파일인 cron table(줄여서 crontab)에 입력 한 명령을 기반으로 일정에 따라 계획한 작업을 실행 하는 데몬입니다. 데몬이란? 사용자가 직접 제어하지 않고 백그라운드에서 돌면서 여러 작 업을 하는 프로그램 구성: crond(데몬) + crontab(제어프로그램) = cronie, vixie-cron(패키지) http://webdir.tistory.com/174 작년 휠세미나 자료 제타위키
crontab 앞으로 계속 나올 단어 Cron 데몬을 작동시키기 위한 table을 설치, 제거, 나열하는 기능을 가진 프로그램임 또는 cron 데몬을 작동시키기 위한 설정 파일 자 체를 의미하기도 함 “cron을 쓴다” = “crontab에 명령어를 입력한다” 라고 생각하면 편하다
Crontab 위치 /etc/crontab: 시스템 전체의 crontab Crontab프로그램을 이용시에는 Username 필드가 들어감 Crontab프로그램을 이용시에는 /var/spool/cron/crontabs에 username으로 저장된다 (데비안 경우) /var/spool/cron에 username으로 저장되기도 함(레드 헷 등) 직접 수정하는 것은 지양해야함
크론데몬 실행시키기 Init(Sysvinit) 이용시 Systemd 이용시 크론 데몬 시작: service cron start 크론 데몬 중지: service cron stop 크론 데몬 재시작: service cron restart Systemd 이용시 크론 데몬 시작: systemctl start cron 크론 데몬 중지: systemctl stop cron 크론 데몬 재시작: systemctl restart cron 실행 되고 있나 확인: ps aux | grep cron cron이 실행될 때 /var/spool/cron/crontabs에 현재 사용자가 지정한 crontab이 있 는지를 참조
기타 설명 Init(Sysvinit), Systemd 란 (매우 간략한 설명) 리눅스 부팅시 가장 처음 실행되는 프로그램 (PID 1) 다른 데몬과 서비스를 실행시키고 관리한다 전통적으로 유닉스에서는 init 사용했음 속도가 더 빠르고, 관리의 편리성 등을 위해 systemd 라는 것을 만듬 최신 대부분의 리눅스 배포판의 기본 init system 이 systemd. (데비안같은 경우 Jessie부터)
Crontab 형식 시스템 Crontab 형식. * * * * * [username] [수행할 명령어] * * * * * [수행할 명령어] 각각의 별에 해당하는 필드는 [분] [시] [일] [월] [요일] 분 : 0-59 시 : 0-23 일 : 1-31 월 : 1-12 (jan, feb 와 같은 이름도 가능) 요일 : 0-7 (0, 7은 일요일), (mon, tue 와 같은 이름도 가능)
Crontab 형식 필드에 * 가 들어갈 수 있음. *는 항상 처음부터 끝까지를 의미함. E.g) 달에 해당하는 필드에 *가 들어가면 1, 2, … 12 와 같은 의미이다 필드에 숫자 범위가 들어갈 수 있음. “-”을 사용하면 됨 E.g) 8,9,10,11을 8-11은 같은 의미임 필드에 리스트가 들어갈 수 있음. “,”를 사용하면 됨 E.g) 1, 2, 4-5, 7 필드에 Step value도 가능함. /숫자를 사용하면 됨 E.g) 0-10/2 는 0, 2, 4, 6, 8, 10와 같은 의미임. E.g) 분에 해당하는 필드에 */10를 기입하면 십 분마다의 의미가 된다.
Crontab 확장 키워드 @yearly :일년마다 실행한다는 키워드, (e.g) “0 0 1 1 *” @monthly : 달마다 실행한다는 키워드 @weekly : 매주 실행한다는 키워드 @daily : 매일 실행한다는 키워드 @hourly : 매시간 실행한다는 키워드 @reboot : 컴퓨터 재시작시 실행한다는 키워드 e.g) @daily ~/backup.sh
예시 */1 * * * * user1 sh /home/user1/every_1min.sh
직접 해보기: 작업 등록 crontab –e crontab –u testuser –e 이것을 입력하면 testuser의 crontab을 수정할 수 있다. (권한이 필요함)
예약 작업 목록 확인 crontab –l 을 하면 현 재 사용자의 crontab 을 볼 수 있다 crontab –l –u testuser 을 하면 testuser의 crontab을 볼 수 있다.
Cron에서 환경변수 SHELL: 등록된 프로그램을 실행시킬 쉘 프로그램 지정 기본값: /bin/sh PATH: cron에서 프로그램을 찾을 때 쓰일 경로 기본값: /usr/bin:/bin 해당 디렉터리에 명령이 포함돼있지 않으면 명령어의 절대경로를 써야 한다 MAILTO: cron이 수행한 작업의 결과를 mail로 보낼 수 있다 설정하지 않은 경우 실행유저에게 메일 전송 설정했는데 비어있는 경우 (MAILTO=""), 메일이 보내지지 않는다. HOME: cron의 home 디렉토리를 설정한다. 기본값: /etc/passwd 에서 적혀있는 것을 따른다. LONGNAME: crontab의 소유주 기본값 수정 방법: crontab에 환경변수=값을 쓰면 된다. http://finerss.tistory.com/46
삭제 현재 사용자의 예약작업을 모두 삭제 crontab -r
몇 가지 TIP Crontab –e 입력하면 vim대신 nano나 emacs, vi 에 디터가 실행이 되는 경우: VISUAL과 EDITOR 환경변수를 바꿔줍시다. export EDITOR=vim export VISUSAL=“$EDITOR” 로그인할 때마다 적용하려면 .bash_profile 파일 에 추가하기
cron 예시 ~$ vi cron.sh #!/bin/bash echo “5 minutes left” ~$ crontab -e * * */1 * * sh cron.sh >> /home/george/time_limit.txt
Cron은 절대 경로로?! 이전 세미나 자료보면 “cron은 시스템에 기본적으로 설치되어져 root에게 만 권한이 주어지기 때문에 ls, mv, cd같은 시스템 명령 이외에는 절대경로 로 입력해 줘야 한다” 라고 나와있지만…. 설명이 모호해서 정리하면 시스템 명령어는 $PATH에 위치하고 있는 명령어라고 볼 수 있음 기본 작업 directory는 사용자 홈 directory이므로 홈 directory밖에서 작업을 하려면 절대경로를 사용해야함 사용자 Crontab에 있는 명령들은 해당 사용자의 권한으로 돌아감. e.g) coearth 의 crontab에서 작업은 coearth 권한으로 돌아감: uid=1004(coearth) gid=1004(coearth) groups=1004(coearth)
* * */1 * * sh cron.sh >> /home/coearth/time_limit.txt * * */1 * * sh cron.sh >> time_limit.txt * * */1 * * sh cron.sh >> ~/time_limit.txt
Cron 예시 2 ~$ crontab -e 0 */1 * * * python ~/some_python_script.sh 0 */5 * * * curl –s 'http://ddns.dnszi.com/set.html?user=coearth&auth=blah'
/etc/cron.allow 그리고 /etc/cron.deny 둘 다 비어있으면 root만 사용 가능함 참고) allow, deny에 동시에 입력되어 있을 경우 사용 가능함
Anacron anacron은 정확한 시간에 작업을 실행하는 용도 가 아니라 매일, 매주, 매달의 작업을 ‘적절한 타 이밍’에 실행하기 위한 명령어이다. cron 작업은 상주형 데몬인 crond에 의해 정기적 으로 실행되지만, anacron은 데몬이 아니다. 누군가가 명시적으로 anacron 명령어를 실행한 타이밍에서 실행이 필요한 작업이 있으면 그 작 업을 실행한다.
Anacron 작업의 실행 간격을 1일 단위로 지정 1일 1회 이상 실행 빈도는 설정 불가, 명시적인 실행 시각 지정 불가 작업의 설정 장소는 /etc/anacrontab만 가능하며, root만 이 설정 가능 작업의 실행 타이밍에 랜덤으로 연장 시간이 추가된다. 장기간 서버가 정지된 경우에는 서버 가동 후에 필요한 작업을 바로 할 수 있다.
끝