티스토리 뷰

Table of Contents

bash shell scripting tutorial -vivek 정리 완료일: 2016/05/07

1 ch. 2

1.1 shell 실행

처음에 os가 로딩되면 로그인 쉘 로딩 됨. /etc/profile에서 시스템 init /etc/bash.bashrc 에서 interactive shell을 실행 etc/bash.logout $HOME.bashprofile -> 유저의 홈에서 각자 shell 띄움.

1.2 shell 이란

linux kernel의 유저 인터페이스로 등장 linux는 linus tovalz 가 만들었다. bash shell (bash) 은 여러 쉘 중 default 로 지정된 쉘로, bourn shell (sh?)을 개조해서 만들었다. shell종류는 여러가지가 있는데 설치된 shell들은 /etc/shells 에서 확인 가능. shebang이라는 #!기호로 시작하는 라인이 스크립트 파일 제일 위에 온다. 이는 사용할 interpreter위치를 명시하는 줄이다. 안적어줘도 default bash shell을 쓸 수 있긴 하지만 비추. #!/bin/bash

1.3 permission

ls -l script.sh chmod +x(755) -> 누구나 실행 chmod u+x(700) -> owner만 실행 ug=rx -> user,group에 대해 rx 권한

1.4 스크립트 실행

chmod +x script.sh ./script.sh 하거나 bash script.sh 하거나 . script.sh . 명렁어는 dot command로 해당 파일을 실행하는 명령. 배쉬 실행에도 몇 가지 옵션이 있다. bash -x script (디버깅 모드) shebang에 있는 라인이 인터프리터 패스인데, 거기에다 실행 옵션을 적어줄 수도 있다. #!/bin/bash -x

2 ch.3 shell variables and env

2.1 system variable

set 또는 env를 입력시 시스템 변수가 출력됨 대표적으로 HOME, HOSTNAME 등..

2.2 variable 사용

${HOME} 은 해당 변수 값을 뜻한다. printf "%s\n" ${HOME} {}는 생략 가능한데 다른 문자와 섞어 쓸 경우 혼동스러울 수 있다. -— {}는 변수를 싸는 것이고, $()는 명령어를 싸는 것이다. $()는 생략 불가. echo "$HOMEIS" -> 아무 값도 없다. echo "${HOME}IS" -> /home/dahyunIS

2.3 default variable

${a:=d} a라는 변수에 값이 지정되어 있지 않는 경우 디폴트 값으로 d를 지정한다. die () { local error=${1:-undefined error} echo "$0: $LINE $error" }
die "file not found" die -> $1 value가 비어 있어서 undefine error

2.4 naming

알파벳 _ 으로 시작 가능하고 알파벳 숫자 _ 조합으로 명명 가능. 값을 지정할때 space 를 두면 안되고 딱 붙여야함. no=10 null variable 정의 가능 vech= 또는 vech=""

2.5 echo

변수 값만 치환하고 문자 그대로 출력

2.6 printf

거의 c에서 쓰는거랑 비슷함. \" -> " %% -> % 포맷팅 문법은 "%w.pL" -> w는 최소한의 필드 길이, p는 소숫점 자릿수, L은 conversion character 로 s(string), d(integer), e(exponential), f(floating point) 가 있다. 그러니깐 var=10.234 "%1.2f" $var -> 10.2

2.7 quoting (expansion)

echo \"${SHELL} $(date) .c\" -> variable, command, wildcard 모두 치환 echo "\"${SHELL} $(date) *.c/"" -> variable, command 치환은 되지만 wildcard ()은 치환 안됨. echo '\"${SHELL} $(date) *.c\"'-> 모두 치환 안됨. backslash를 특수 기호 앞에 붙이면 특수 기호 기능이 상실되고 그 문자 그대로 나옴.
현 디렉토리에 asdf1.c asdf2.c 가 있으면 find . -name *.c 라고 할 때 에러가 난다. 왜냐면 쉘에서 find 함수에 전달되는 parameter는 *.c가 아니고 asdf1.c asdf 2.c 이기 때문이다. 레귤러 익스프레션 파싱은 find 함수 안에서 되야 한다. 그러므로 find . -name "*.c" 혹은 \.c 이렇게 적어줘야 맞다.

2.8 backslash 기타 기능

\v vertical tab \\ backslash \e escape char \a alert \' single quote \n new line
\ 는 continue command on next line 기능도 있음.. 매크로에서 처럼. echo " asdf \ > asdf asdf \ asdf" \ 는 물론 스크립트 파일 안에서도 사용 가능.

2.9 export

a=b c=d export "$a" bash 쉘에서 bash를 치면 새로운 bash가 뜬다. (창은 그대로고) ps를 하면 child bash가 생긴 것을 확인 할 수 있다. 여기서 a는 parent의 것을 전달 받음. c는 없음. export -p를 하면 전달받은 variable들이 죽 리스팅 되는데 특이한 점은 여기에 시스템 변수들도 있다는 거다.

2.10 unset

설정한 변수 삭제

2.11 read ( user input)

read 라는 명령어가 있는데 scanf랑 거의 같다. read -p "enter your name and gender: " name gender enter your name and gender: 가 뜨고 enter your name and gender: dahyun female 입력하면 name 과 gender 가 각각 저장된다. option: -p: prompt message -t : timeout , -s : handling input as secret (password)
다음 스크립트에서 read -p "who are you" name echo "$name" 하고 사용자가 Me Mike Emma라고 입력하면 name에 다 저장이 되는데 IFS로 분리 가능. (???? 라인은 알겠는데, 단어는 ? 라인이랑 단어 구분이랑 다른거 같던데?) -> $IFS internal field seperator 라는 변수가 있음. cat -etv <<<"\(IFS" ^I\) $
-etv -> tab, end 컨트롤 문자를 보여줘 <<<는 "$IFS"가 파일이 아닌 스트링이기 때문에 인풋 스트림을 만들어줘야 함.
여기서 ^I$ 는 tab and newline (white space 아니다..) $는 end of line
즉 IFS는 token delimeter 가 들어있다.
portals="naver daum yahoo" read -r p1 p2 p3 <<< portals 하면 p1, p2, p3에 각 포탈들이 쪼개져서 저장된다.
그러니까 변수를 쪼갤 일이 있으면 IFS에 들어있는 delimeter로 쪼개진다. IFS는 변경 가능하다.
oldifs=$IFS IFS=: :를 delimeter 로 쪼개고 나서 IFS=$oldifs

2.12 arithmetic operation

$((expression)) 위의 형태로 arithmetic operation을 할 수 있다. expression형태나 할 수 있는 연산은 c에서와 같은 형태.
bitor, shift, compare, conditional operator(?:) 다 됨..

2.13 readonly (constant var)

shell 끝날 때 까지 살아있고, 변하지 않고, 지울 수 없는 변수 readonly DATA=asdf 하고나면 overwrite이나 unset 불가능

2.14 variable null check

만약 parameter 변수가 필요한 시점에 변수 안에 값이 없을 경우 null check가 필요. 스크립트 안에
path=${1:?Error command line argument not passed} -> argument 1 로 전달되는 값이 없으면 스크립트를 멈추고 위 스트링을 출력한다.

2.15 customize the bash shell environments

customizing -> prompt를 커스터마이징 하거나 search path, environment variables 등을 미리 세팅한다.
변수 종류는 local, environment 두 가지. export 하지 않는 이상 쉘에서 정의한 변수는 local변수임. environment variable는 서브 프로세스에 전달 되는 변수다.
쉘 build in command는 set 명령어로 볼 수 있고 bash가 정의한 변수들은 모두 대문자로. man bash 를 통해 bash가 정의한 environment 변수를 볼 수 있음
export를 이용해 local 변수를 environment var로 만들면 env에 등록됨. -> export 로 해당 변수 편집 가능 !!<- 하지만 주의 해야겠지 잘못되면 man bash 참조.
echo $PATH /usr/local/sbin:/usr/local/bin <- output exprot PATH=/usr/local/sbin:/usr/local/bin:/usr/games
env 입력 시 environment var 모두 출력.
주요 einvironment var HOME : home dir path PATH : executable serch path PWD : current working dir
which [command]: 현재 환경에서 실행 될 수 있는 실행 파일의 path 를 출력 whereis [command]: binary, source, man page path 출력 whatis [command]: command 에 대한 간단한 설명

2.16 command history

bash는 커맨드 히스토리를 ~/.bashhistory에 저장하고 있음. history 라는 built in command로 출력해 볼 수 있음. 그런데 history는 built in이긴 하지만 set 으로 overwrite가 가능.
방향 키로 이전 커맨드를 다시 띄울 수 있음. C r : reverse-i-search 매칭 되는 커맨드 라인을 reverse i search로 찾음. !!: 직전 커맨드를 불러옴 !somethig: 히스토리에서 somethig을 reverse-i-search 하고 가장 처음 매치되는 커맨드를 불러옴. history를 입력하면 번호 + 명령이 나오는데 ![history line number] 입력하면 해당 라인 커맨드를 불러옴.

3 ch3-2

3.1 path name expansion

3.1.1 curly baraces {}

대체 문을 만듬.
주의할 점은 안에 comma랑 단어 모두 붙여 써야함.
echo I like {tom,jerry} I like tom jerry (이거는 잘 모르겠다. )
echo file{1,2,3}.txt -> file1.txt file2.txt file3.txt
echo file{1..5}.txt rm -v hello.{sh,py,pl,c} <- 이런 명령에서 굳이 파일이 존재하지 않아도 된다.

3.1.2 wildcards

  • : 아무 스트링. null도 괜찮다.
? : 하나의 아무 char […]: 괄호 안 중 하나라도 맞춰라
text?.[ch] -> text2.h text3.c

3.2 create and use aliases

alias는 그냥 커맨드 쇼트컷임. 명령어를 alias 로 저장할 수 있다. alias c='clear' alias cp='cp -i' #옵션, 기타 argument또한 저장 가능 unalias c # 커맨드 c alias를 없앤다. unalias -a # 전부 unalias
영구적으로 alias를 설정하는 방법. 모든 유저 -> etc/bashrc 또는 /etc/profile.d/useralisas.sh (파일 생성 해야한다) 개인 -> /$HOME.bashrc 수정
alias로 expand시키지 않으려면 backslash를 이용하거나 ""을 이용한다. alias는 var이 아니라서 expand 안됨. /ls 또는 "ls"

3.3 tilde

~ : HOME ~+ : PWD (현 path) ~-: OLDPWD (이전에 있던 path)

3.4 startup scripts

3.4.1 script execution order

etc/profile: 처음에 리눅스 시스템 환경에서 처음으로 돌아가는 스크립트 /etc/profile.d: etc/profile에서 이 폴더 안에 있는 스크립트를 순서대로 실행 시킨다. ($HOME).bashprofile: 이 파일이 유저 단위의 배쉬 설정에 해당되는데 이 파일은 또 ~/.bashrc를 부른다. 스크립트가 순차적으로 불리는데, 최근에 불린 스크립트에서 수정한 것이 이전 설정을 overwrite한다.
bashrc 파일을 설정해 함수, alias, var, path, default editor 등을 수정할 수 있다.
~/.bashrc를 열고
alias vi='vim'
입력 후 닫는다. 설정을 로딩하기 위해 ~/bashrc를 쳐주거나 bash를 다시 켠다. alias를 입력하면 설정한 alias를 볼 수 있다.

3.4.2 dot file 보기

ls -a 를 하면 dot file 까지 list 됨.

3.5 changine bash prompt

prompt는 터미널에 커맨드 입력받는 줄 앞에 프린트되는 문구다. $PS1에 저장되어 있다. echo \(PS1 /@/h: \w\\)
PS1도 var로 수정이 가능하다. PS1='command:'

3.5.1 backslash-escaped

수정시 backslash-escaped 문자를 사용할 수 있는데 많이 쓰이는 것은 \h : host name \n : neline \t : current time in 24-hour HH:MM:SS format \d : date in weekday-month-date format \u : username \v : bash version \w : current workin directory \! : hlistory number of command \$ : if the effective uid is 0, a # otherwise a $ \e : escpate ascii \[ \] : 이 괄호 안에 있는 애는 non-printing sequence 인데 .. 보기 좋으라고 쓰는 듯?
export PS1='\[\e[1;32m\][\u@\h \w]\$\[\e[0m\]' 이게 노말 유저 어카운트를 초록색으로 설정하는 명령이라고 함. ~/.bashrc에 적어주면 항상 유지 됨.

3.5.2 PROMPTCOMMAND variable

이 변수를 설정해 놓으면 특정 명령이 실행되고 나서 이 PROMPTCOMMAND가 실행됨. $ PROMPTCOMMAND="echo asdf" asdf $date Tue Oct 20 23:30:21 IST 2009 asdf # 요거.

3.5.3 setting shell options

쉘 내장 기능들이 있고 이 기능을 쓸지 말지 결정하는 옵션이 있다. 이 옵션은 set, shopt 두 커맨드로 끄거나 켜는 것이 가능하다.
set -o -> 옵션 리스트가 뜬다. set -o option -> option이 켜진다. set +o option -> option이 꺼진다.
shopt -p -> 옵션 리스트가 뜬다. shopt -s option -> option이 켜진다. shopt -u option -> option이 꺼진다.
예를 들면 cdspell 이라는 옵션이 있는데 이 옵션의 디폴트는 꺼져있는 것이다.
shopt -s cdspell cd /etcc /etc 오타를 고쳐서-> etc로 이동하는 cdspell의 기능.

3.5.4 bashrc

~/.bashrc에다가
shopt -q -s cdspell set -o notify export HISTSIZE=5000 export JAVAHOM/usr/lib/jvm/java-5-sun/jre export PATH=$PATH:$ORACLEHOME/bin:$HOME/bin:$JAVAHOME/bin source /etc/bashcompletion #Turn on bash command completion alias grep='grep –color' alias ipconfig='ifconfig'
이런 식으로 설정

4 ch.4 conditionals execution

4.1 bash structured language constructs

arithmetic operation 에서 bool 연산 echo $((5!=2)) echo $((5<2))

4.2 test command

file attribute, string, arithmetic comparison에 사용할 수 있다.
condition? true-command : false-command 랑 비슷함. 아래와 같이 쓸 수 있다. test condition test condition && true-command test condition || false-command test condition && true-command || false-command
test 5 -gt 2 && echo "yes" #-gt: greater, -ge : greater or equal -eq: equal -lt test 5 != 10 && echo yes || echo no test -f /etc/reslv.conf && echo "file found" || echo "file not found"

4.3 if

if condition1 # if [conditions] then cmd1 elif condition2 then cmd2 elif condition3 then cmd3 else cmd4 fi
if test var == val then cmd1 else cmd2 fi
#!/bin/bash read -p "enter a password" pass if test "$pass" == "jerry" then echo "pass verified" fi
-> nesting 도 가능하다. 인덴트는 알아서 잘 하자.

4.4 exit status of a command

커맨드는 그 수행을 하고 리턴 값이 있다. 리턴값이 $?에 저장된다. 0은 정상 종료를 의미하고 1-255 의 값은 에러를 의미한다. 커맨드를 입력한 후에 echo $? 치면 리턴값이 출력된다.

ls -l /tmp status=$? echo "ls command exit stats - $status"
주의할 점은 ! 리턴 값이 0이면 true 이다. !!!!

4.5 logical and && and or ||

command1 && command2 command1 이 true (0 을 리턴) 해야지만 command2가 실행된다.
command1 || command2 command1 이 false (non-zero 을 리턴) 해야지만 command2가 실행된다.

4.6 logical not !

! expression [! expression]

4.7 numeric comparison

eq : equal ge : greater or eq gt : greater le : less lt : less than ne : not equal

4.8 string comparison

그냥 =
STR1 = STR2 STR1 != STR2

4.8.1 기타

-z str : str 길이가 0인가.
-e file : 파일이 있는가 -f file : 파일이 있고 정식 파일인가 (? regular file) -g file : true if file exists and is set group id -l file : true if file exists and is a symbolic link -p file : true if file exists and is a pipe -r/w/x file : true if file exists and is readable/writable/executable 등 ..
-d : 디렉토리가 있는가.
if test -z $pass then echo "no pass entered" exit 1 fi
[! -f /path/to/file] && echo "file not found"

5 ch4-2

5.1 arguments

$0: 커맨드나 스크립트 이름 아규먼트는 순서대로 $1 $2 .. $9 등 순차적으로 접근 가능 $# : 총 아규먼트 수 $* 또는 $@ : 모든 커맨드라인 아규먼트 값들. 둘의 차이는 $*의 경우는 아규먼트 사이에 그냥 스페이스($@)가 아닌 IFS안에 들어있는 value를 넣는다. IFS에 ,들어있으면 아규먼트 사이에 ,가 있는 형태로 나열된다.

5.2 parameters set by the shell

$* $@ :arguments $# : number of parmas $- : flags supplied to the shell $? : return value of prev command $$ : process number of current shell $! : process nuber of the last background command
이러한 특수 parameter에 특정 값을 지정해 넣는 것은 불가능하다.

5.3 usage command 예시

[$# -eq 0] &&{echo "usage: $0 username" ; exit 1;}

5.4 exit command

exit N N 을 리턴 하며 종료한다. c 의 return과 비슷.

5.5 case 문

case $var in pattern1|pattern2) cmd1 … cmdN ;; pattern3|pattern4|patter5) cmd1 … cmdN ;; patter6) cmd1 … cmdN ;; # break *) # wildcard esac # 이거 case를 거꾸로 쓴거네 ㅋㅋㅋ

5.6 dealing with case sensitive pattern

case나 condition에서 대소문자 구분이 중요한 스크립트에서 대소문자 처리를 하는 방법

5.6.1 tr 함수 사용

echo "TeSt" | tr '[:upper:]' '[:lower:]'
var="TesT" tr '[:upper:]' '[:lower:]' <<< "$var"

5.6.2 regexp 사용

tar Tar tAR 등을 위해 [Tt][Aa][Rr]으로 매치
case $1 in [Tt][Aa][Rr]) … ;;

5.6.3 nocasematch option 사용

shopt -s nocasematch 이 옵션은 case 문이나 [[ conditional command 에서 케이스 insensitve 하게 매치하게 한다.
shopt -s nocasematch 을 케이스 문 앞에 쓴 뒤 shopt -u nocasematch 를 케이스 문 끝에 다시 써준다.

6 ch.5 bash loops

6.1 for loop

6.1.1 for syntax

for var in item1 item2 … itemN do cmd1 … cmdN done

6.1.2 for var in list-of-values

for car in bmw ford toyta for command in date pwd df

6.1.3 for var in $fileNames

files="/etc/passwd /etc/group /etc/shadow" for f in $files do [-f $f] && echo "$f file found" ||echo "error - $f file missing" done

6.1.4 for in array

Array=(./*.conf) for var in "{Array[@]}"
for i in {1..10} do echo "$s * $i = $ (($i * $n))" done

6.1.5 for var in $(Linux-command-name)

for 문에 명령어 사용하려면 $()로 반드시 감싸야 한다.
for f in $(ls /tmp/*)

6.1.6 for ((EXP1; EXP2; EXP3)) # c style

for ((i = 1; i <=5; i++)) do …. done

6.2 while loop

6.2.1 while loop syntax

while [condition] do cmd1 … done
while (($n <= 5)) do echo "$n" n=$((n+1)) done
done 끝에 있는 걸 IFS로 잘라서 line에 저장한다. IFS -> 한 라인
while IFS= read -r line # -r 옵션은 백슬래쉬를 문자 그대로 읽겠다는 뜻 (while IFS= read -r filed1 filed2 filed3 ) do cmd on $line …. done < "/path/to/file"
file=/etc/passwd while IFS=: read -r user enpass uid gid do [$uid -ge 500] && echo " $user …" done < $file

6.3 infinite while loop

쉘에 true, false, : 내장 커맨드가 있다. true: successfully (always returns exit code 0) false: unsuccessfully (always returns exit code 1) \ : : this command do nothing (always returns exit code 0)
infine loop 를 사용하려면 condition에 true 나 :을 적어줄 수 있다. (false는 아무 것도 안한다.) 근데 여기선 true 보다 :이 recommended.
while : do clear read -p "Enter [1 - 4] " choice case $choice in
  1. echo 1 ;;
  2. echo 2 ;;
*) echo 3 ;; esac done

6.4 until loop

while 이랑 비슷한데, 가장 큰 차이는 while은 condition 이 0를 리턴할 때까지 실행되는 반면 until은 nonzero 를 리턴할 때 까지 실행되며, 최소 한 번은 실행된다.

6.4.1 until loop syntax

while 자리에 until 써준다.

6.5 select loop

prompt 명령의 일종인 PS3을 위한 루프다. 선택지들을 화면에 보여주고 선택을 할 수 있도록 한다.
유저 인풋으로 선택지를 받으면 루프가 한 번 실행되고 다시 인풋을 받는 상태로 돌아간다.
PS3="ENTER number: " select country in korea japan china exit do case $country in korea) echo "korea" readEnterKey ;; japan) echo "japan" readEnterKey ;; china) echo "china" readEnterKey ;; exit) break ;;
*) echo "try again" readEnterKey #enter 키 입력을 받는 것을 기다린다. done
->
  1. korea 2) japan 3) china 4)exit
ENTER number: 1 korea

6.6 break

break 써주면 루프 탈출인데 특이 한 점은 argument 숫자를 주면 루프를 그 숫자만큼 탈출할 수 있다.
for in do for in do break 2 done done

6.7 continue

6.8 command substitution

$() 하면 커맨드가 치환.
NOW=$(date) echo "$NOW"
for f in $(ls /etc/*.conf) 도 가능하지만 추천은 for f in /etc/*.conf

7 ch.6 shell redirection

linux 의 모든 것은 파일이다. 하드웨어 장비도 파일인데 0: input (stdin)
여기서 <
1: output (stdout)
여기서 >
2: error (stderr)
여기서 2>
> : stdout 1> : stdout 2> : stderr >> : append &> : stdout + stderr
이 세 숫자는 posix number, 미리 저장되어있는 fd임.

7.1 /dev/null /dev/zero로 오는 (> 2> &>) 스트림은 쉘이 다 지워 버린다.

예시 grep vivek /etc/passwd >/dev/null && echo "found" || echo "not found" 원래는 grep의 결과가 echo 이전에 함께 출력된다.

7.2 HERE document

7.2.1 syntax

command <<HERE text1 … # 여기서 부터 textN $varName HERE # 여기까지 현 소스
<< 는 쉘에 입력하는 인풋이고 HERE HERE는 어떤 단어이고 아랫 줄부터 이어지는 현 소스에 대해 커맨드를 실행함. 인풋을 주는 거임.
아래는 단어 수를 세는 명령 echo 'This is a test.' |wc -w 4
wc -w <<EOF > This is a test > Apple juice > EOF 6

7.2.2 예시 - 백업 상태를 메일로 보내는 스크립트.

#!/bin/bash tar -cfv /dev/st0 /www /home 2>/dev/null [$? -eq 0] && status="success" || "failed"
mail -s 'backup status' vivek@nixcraft.co.in <<ENDOFMAIL the baackup job finished end date : $(date) hostname : $(hostname) status : $(status)
ENDOFMAIL

7.3 here strings

7.3.1 syntax

command <<<$word command arg1 <<<"$word"
grep arg1 arg2 의 경우 arg1은 찾고자 하는 문구, arg2는 문구를 찾으려는 파일이다. 근데 파일대신 스트링을 바로 넣고 싶은 경우
target file 대신 <<<"target string"을 적어준다.
var=asdf grep "a" "asdf" # 안됨 grep "a" $var # 안됨 grep "a" <<<"adf" #됨 grep "a" <<<var #됨
다른 많이 쓰는 방법으로 쉘파이프가 있다. echo $var | grep -q "a"

7.4 stdout

date > now.txt sudo bash -c "cat file.txt >/dev/lp0" echo "today is $(date)" 1> tmp/now.txt echo "goodmorning" 1>> tmp/now.txt

7.5 stdout and stderr

command &> file command > file 2>&1 # stdout을 파일로, stderr를 stdout으로 command > /dev/null 2>&1 # command stderr stdout 둘 다 버림

7.6 avoid overwriting to files

set -C 하면 > 로 인한 파일 오버라이트 방지. 오버라이트 허용하려면 set +C
echo "a" >test.txt set -C echo "b" >test.txt # 실패. 오버라이트 안됨. set +C echo "c" >test.txt # overwritted

7.7 reading and writing from files

sort < output.txt # output.txt 를 읽는다. sort < output.txt > sorted.txt #output.txt를 읽어 소트하고 sorted.txt에 저장한다. (인풋 아웃풋 순서가 바뀔 순 없다.)

7.8 asigns the file descriptor to file

7.8.1 syntax

exec fd> ouput.txt 하면 fd 번호에 w파일을 지정하는 것. exec fd< input.txt 하면 fd 번호에 r파일을 지정하는 것. exec fd<> input.txt 하면 fd 번호에 rw파일을 지정하는 것. write : command >&fd read command <&fd
fd 지정 해제는 exec fd<&- 단 fd는 0, 1, 2는 이미 지정되어 있으므로 3이상이어야 한다.

7.8.2 read from the file descriptor

read -u option은 키보드가 아니라 파일로 부터 읽는다는 옵션.
read -u fd var1 var2 … varN
while IFS= read -u fd -r line do command1 on $line command N on $line while

7.8.3 shell script to display its own fds

#!/bin/bash
file exec 3< /etc/resolv.conf
file exec 4> /tmp/output.txt
read -u 3 a b
echo "my pid is $$" mypid=$$
echo "currently open files by $0 scripts" ls -l /proc/$mypid/fd
exec 3<&- # 지정 해제 exec 4>&-

7.8.4 shell script to read file line by line

#! /bin/bash FILE="$1" [$# -eq 0] && {echo "usage: $0 filename"; exit 1;} [! -f $FILE ] && {echo "error file $FILE is not exists"; exit 2;} [! -r $FILE ] && {echo " $FILE is not readonly"; exit 3;}
exec 3<$FILE
IFS=$(echo -en "\n\b")
while read -u 3 -r line do echo $line done
exec 3<&- exit 0

8 ch. 7 pipes and filters

8.1 linking commands

cmd1; cmd2 seperate commands that are executed in sequence. cmd1 & command runs in background cmd1 && cmd2 cmd2 runs if and only if cmd1 returns true. cmd1 || cmd2 cmd2 runs if and only if cmd1 returns false. cmd 1 | cmd2 | is pipe. cmd1's output goes to input of cmd2

8.2 job control

fg : palce job in the foreground bg : place job in the background jobs : lists the acitve jobs on screen.
find /nas -name "*.mp3" > /tmp/filelist.txt & # background로 find 실행

8.3 pipe examples

mount | column -t
who | wc -l
tar zcvf - /home | ssh user@server "cat > /backup/homefs.workstation.tar.gz"
(cat에 input argument)리모트 세션에다가 백업파일 저장.
echo "TesT" | tr '[:upper:]' '[:lower:]'

8.4 filters

awk cut grep gzip head paste perl sed sort split strings tac tail tee tr uniq wc
등 필터와 파이프를 잘 사용하자

8.5 ch 8.

9 ch. 8 Traps

trap command to catch signals and handle errors under linux shell scripts

9.1 process

A process is to perform specific job. it has unique id, PID PID starts from 0 to 65535, pid 1 is always init process, which is first process started at boot time.
A parent process is a linux process that has created one or more child processes. In UNIX every process is created using fork and exec method.
type command in the shell -> shell makes child process : fork. duplicate shell's pages of memory and then execute the command.
(근데 페이지 듀플리케이트는 copy-on-write로 이뤄짐)

9.1.1 process의 상태

fork (parnet) –————> wait (parent) -> exec(child) -> exit (child)
D - uninterruptible sleep : process is sleeping and cannot be bring back until an event occurred. R - running S - sleeping : waiting for an event or a signal T - traced or stopped : stopped by signals such as SIGINT or SIGSTOP Z - zombile or defunct : remaing dead process caused by no removal by parent process
ps -C processName -o pid=,cmd,stat -> pid cmd stat 이렇게 출력 됨. CMD STAT 1644 /usr/bin/php-cgi S

9.2 how to view processes

9.2.1 ps

ps ps aux | less ps aux | grep "process-name" pas aux | grep "httpd"

9.2.2 pstree

pstree # display a tree of processes

9.2.3 pgrep

pgrep은 현재 running processes에 대해 해당 조건에 맞는 것을 찾아줌. pgrep -u vivek php-cgi # processes called php-cgi, ownd by vivek user pgrep -u vivek,krish # list processes owned by bibek or krish

9.3 sending signal to processes

9.3.1 kill

kill의 기본 시그널은 TERM인데, 다른 시그널도 선택가능하다. kill -l # list options
  1. SIGHUP 2)SIGINT 3) SIGQUIT …..
  2. SIGCONT …
  3. SIGTERM …
9)SIGKILL ….
  1. SIGSTOP ….
커맨드는 이 시그널을 받고, 처리하는 코드가 있어야 시그널을 처리함. 없으면 땡.
많이 쓰는 시그널은, SDIGHUP (1) : hangup detected on controlling terminal or death of controlling process SIGINT (2) : interrupt from keyboard SIGKILL (9) : kill running process SIGSTOP (19) : stop process SIGCONT (18) : continue process if stopped
시그널 번호 조회 : kill -l SIGTSTP # signal name as list option arg 전체 시그널 리스트 조회는 : more /usr/include/linux/signal.h (? 안나오는데?)
kill -9 1234 # pid 1234에 sigkill signal 을 보낸다. kill -KILL 1234 kill -SIGKILL 1234

9.3.2 killall : kill processes by name

killall fiefox-bin # 기본 시그널은 SIGTERM이다. killall -s SIGKILL firefox-bin # SIGKILL을 시그널로 보낸다.

9.3.3 pkill : kill process

kill에 옵션이 추가된 버전. process name, user name, group name, terminal, uid, euid, gid 등을 이용해 끌 수 있다.
pkill -KILL php-cgi pkill -KILL -u vivek php-cig pkill -HUP sshd

9.4 terminating processes

Ctrl c 누르면 foreground 프로세스에 TERM시그널을 보낸다. (SIGTERM) background 프로세스를 죽이려면 kill -9 pid Ctrl z 누르면 foreground 프로세스를 suspend한다. 다시 resume하려면 fg command를 사용한다. fg jobid fg 1
SIGTERM의 경우 트랩이 가능한 시그널인데, 트랩을 걸게 되면 프로세스는 종료되는 것이 아니라, 트랩 명령을 수행한다. trap 이 가능하고 불가능한 시그널이 있는데 트랩 불가능인 시그널은 무시도 불가능하고 시그널 명령을 수행해야 함. SIGKILL (9), SIGSTOP (19) sigkill 받으면 그냥 프로세스가 꺼진다.

9.5 trap statement

시그널을 받았을 때 처리 문구.

9.5.1 syntax

trap arg signal trap command signal trap 'action' signal1 signal2
trap 'echo "exit 0 signal detected."' 0
쉘 안에서 트랩을 설정할 수 있는데 trap "echo "asdf"" 0 1 2 3 15
설정후 trap 하면 설정된 트랩 리스트가 나온다. ctrl c 누르면 echo "asdf" 가 실행되는 것을 볼 수 있음.

9.5.2 clear trap

trap - signal1 signal2 # 트랩을 지울 대상 시그널(번호나 이름)을 적는다. shell script 안에서 트랩을 설정했으면 마지막에 꼭 해제를 해주자!
trap "echo "disabled signal"" 0 SIGINT ..somethig… trap - 0 SIGINT

9.5.3 die function. use the trap statement to catch signals and handle errors

die는 죽기 전 에러 처리 등을 위한 함수.
예시 1) file="/tmp/data.$$" #arguments string
die () { echo "$@" #arguments string exit 2 }
[! -f $file] && dile "$0: file $file not found" || echo "$0: file #file found."
예시 2) dile () { echo "…" } trap 'die' 1 2 3 15

9.6 subshell

() 안의 커맨드는 모두 서브쉘에서 실행된다. 터미널에 치는 일반 커맨드도 서브쉘이라고 보면된다.
$BASHSUBSHELL: 몇 번째 서브 쉘인지 나타냄. 최상위는 0, 그 아래 서브쉘은 1, … echo "curr: $BASHSUBSHELL"; (echo "sub: $BASHSUBSHELL") curr: 0 sub: 1

9.6.1 exporting functions and variables

서브 쉘은 부모 쉘의 정의된 변수, 함수를 export 해야만 상속받을 수 있다.
WWWJAIL=/apache.jail export WWWJAIL # 변수 export die() {echo "$@"; exit 2;} export -f die # 함수 export /etc/nixcraft/setupjail -d cyberciti.com

9.6.2 use exec command to avoid subshell

The exec command replaces this shell with the specified program without swapping a new subshell or process.
exec command
#redirect the shells stderr to null exec 2>/dev/null

9.7 dot command (source command랑 같음 ????)

. script.sh 이런식을 사용하는데 dot command는 스크립트를 읽어와 current shell 에서 실행하게 되는데 이건 스크립트 안에서만 수정되는 것이아니라, 스크립트 종료후에도 current shell variable이 바뀌어 있다. exec 과는 차이는 source는 실행한 파일의 변수와 함수를 라이브러리에 추가한다는 것!!!
실행하는 주체가 쉘인 경우에 sh에 +x permission 을 설정하지 않아도 됨… (exec source .) ./script.sh 의 경우는 chmod +x 필요..

9.8 compound command

9.8.1 ()

( list ) ( cmd1; cmd2)
() 의 경우 :
hostname ; date; who | wc -l >tmp/output.txt 는 who | wc -l 의 결과만 redirect 된다.
(hostname ; date; who | wc -l) >tmp/output.txt 는 세 커맨드 모두가 redirect 된다.

9.8.2 {}

{ cmd1; cmd2} 이 경우에는 모든 커맨드가 current shell environment에서 돌아가는 것과 같게 해 준다. [$# -eq 0] && {echo "usage: $0 filename"; exit 1;} # $0는 사실 parent shell variable…

9.9 exec

서브쉘 대신 현 쉘에서 돌아가게 한다. 보통 환경변수 등을 설정하는 후 커맨드를 실행하는 래퍼 스크립트에 많이 사용한다.
PHPCGI=/usr/local/bin/php-cgi export PHPFCGICHILDREN=4 export PHPFCGIMAXREQUESTS=1000 exec $PHPCGI

10 ch. 9 Functions

xrpm() { rpm2cpio "$1" | cpio -idmv } hello() {echo "hello world"}

10.1 decleare

declare -f : 정의된 함수들을 볼 수 있다. declare -f fucntionName : functionName의 함수 정의를 볼 수 있다.
unset 명령으로 함수 정의를 뺄 수 있다. unset functionName

10.2 define function syntax

10.2.1 1

name () {
} yday () { date –date='1 day ago' }

10.2.2 2

name {
}

10.2.3 3

name() compoundcommand yday() { date –date='1 day ago';}

10.3 writing function

초기에 정의된 함수는 /etc/init.d/functions 파일에 들어있다. less /etc/init.d/functions 으로 확인 가능.
모든 쉘 함수는 커맨드로 사용할 수 있다.
함수 정의가 함수 사용보다 앞에 와야한다. 다만 recursive function 사용은 가능하다. foo () { … foo … }

10.4 function 백그라운드 실행

커맨드와 마찬가지로 &을 이용해 백그라운에서 실행할 수 있다. name () {
}
name &

10.4.1 source

스크립트의 함수는 . 또는 source로 반드시 로딩을 먼저 해야 한다. 그러면 정의된 함수들은 쉘의 라이브러리에 추가 되게 된다. . 는 물론 다른 스크립트 안에서 사용할 수 있다. source 커맨드는 현재 쉘에 함수들을 로딩하고 스크립트를 실행한다.
source functions.sh source functions.sh WWWROOT=/apache.jail (directory를 적어주면 안에 파일 네임이 죽 어레이로 들어간다. argument로 인덱스 주어서 접근 가능)
. functionscript.sh
funcname arg1 arg2

10.5 function shell variables

$1 $2 .. $N 은 parameter or argument of function $0 는 항상 쉘 스크립트 이름. $* $@ 는 모든 parameters or arguments $# 파라미터 수.
$0 는 쉘 스크립트 이름이고, 함수 이름은 아니다. 함수 이름의 경우.. FUNCNAME을 이용해 구할 수 있는데 FUNCNAME 은 실행 중인 함수 스택정보를 담은 정렬이다. 현재 실행되고 있는 함수는 FUNCNAME 의 인덱스 0에 있다.
backup () { local d="$1" [[-z $d]] && {echo "${FUNCTNAME}() : directory name not specified"; exit 1; } }
backup $1

10.6 local variable

함수 안에 정의 된 변수도 기본은 전역 변수이다. 함수 안 스코프로 변수를 만들려면 local 을 붙여줘야 한다.
varglobal=3 varlocal=4
function name () { varglobal=$1 # 이전에 정의된 값이 바뀐다. local varlocal=$2 # 이전에 정의된 값이 안 바뀐다. }

10.7 예시

declare -r PASS=/etc/passwd
die () { local message="$1" local exitCode=$2 echo "$message" ["$exitCode" == " "] && exit 1 || exit $exitCode
}

10.8 return value

return N 함수를 종료시키고 N을 리턴한다. 특이한 점은 N 이 명시되지 않을 경우 리턴 값으로는 이전 실행한 커맨드의 리턴 값이 들어있게 된다.

11 ch. 10 interactive

dialog 를 apt-get 으로 설정해서 dialog 명령을 통해 dialog box를 만들 수 있다.
menu box, progress bar (gauge box) 등을 dialog명령을 통해 만들 수 있다.
dialog –title "copy file " – gauge "copying file … " 10 75 < <( n=${#DIRS[*]}; i=0 for f in "${DIRS[@]}" do ….

12 기타

12.1 read options

-p prompt -t timeout -u fd -d delim continue until the first character of delim is read, rather than newline -r do not allow backslashes to escape any character -e use Readline to obtain the line in an interactive shell -p prompt output the string PROMPT without a trailing newline before attempting to read -n nchars return after reading NCHARS characters rather than waiting for a newline, but honor a delimiter if fewer than NCHARS characters are read before the delimiter

12.2 read line 과 변수 범위! (어려움)

script file 안에서
1번 ) while IFS= read -u fd -r line
do command1 on $line command N on $line while
2번 ) IFS=$(echo -en "\n\b") #? while read -u 3 -r line do echo $line done
3번 ) while IFS= read -u fd -r line
IFS를 리드 라인에 같이 쓰는 것은 따로 분리 해서 쓰는 것과 다르다.
1번 enva=foo # 상위 쉘에서만 유효한 변수 선언 enva 사용하려면 export enva 필요! command # sub shell
2번 enva=foo; command # environment variable을 바로 건든다고 한다. 그래서 이 형태는 원래 설정으로 돌려놓을 수 있게 백업이 필요.
3번 enva=foo command # 두 명령이 같은 서브 쉘에서 처리 됨. 하위 쉘에서는 변수 선언이 있지만 상위 쉘은 없다.
리드는 한 줄 씩 읽는 게 기본이고, 한 줄을 다시 워드로 쪼갤 때는 IFS 에 들어있는 delimeter 사용.

12.3 file command

12.4 echo options

-n do not append a newline -e enable interpretation of the following backslash escapes -E explicitly suppress interpretation of backslash escapes

12.5 export options

Author: dahyun
Created: 2016-06-12 일 15:26
Emacs 24.5.1 (Org mode 8.2.10)

'Programming tips > language' 카테고리의 다른 글

자바 성능 튜닝 이야기 요약 (ch1 - 8)  (0) 2018.03.31
c coding convetion  (0) 2018.03.31
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함