p347 배열
배열명=(원소1 원소2 원소3)
배열선언시 소괄호()를 사용해야하고, 안에 원소 나열시 공백으로 구분한다
${#배열명[*]} : 배열의 길이
${배열명[$i]} : 배열의 i번째값
--스크립트
[user@localhost ~]$ cat array.sh
#!/bin/bash
book=(김태용 인연 운명)
book[3]="test"
i=0
while [ $i -lt ${#book[*]} ]
do
echo ${book[$i]}
let i=i+1
done
--실행결과
[user@localhost ~]$ ./array.sh
김태용
인연
운명
test
선언한 함수를 제거하고싶다면?
unset -f 함수이름
p354. 입출력 리다이렉션
fork() 와 exec() 차이?
- fork 는 자식쉘을 복사하여 실행. 자식이 작업을 수행하고, 작업이 끝나면 자식은 종료됨
- exec은 현재 로그인쉘의 세그먼트가 ls로 교체되어 수행 후 종료된다. (즉, 자식이 아니라 내가 수행함)
ex)
$ exec ls
p356. exec 사용용도
예)
-- 스크립트
[user@localhost ~]$ cat mylog.sh
#!/bin/bash
exec 3>mylog <--파일디스크립터 3번을 정의함, (3번 파일디스크립터를 정의하는데 입력은 mylog 파일로부터 받는다)
echo "exec test start"
who >&3 <-- (who 결과를 3번 파일디스크립터 - 즉 my log - 로 전달)
date >&3 <-- (date 결과도 3번 파일디스크립터 - 즉 my log - 로 전달)
echo "exec end" >&3 <-- (echo 결과도 3번 파일디스크립터 - 즉 my log - 로 전달)
-- 실행결과
[user@localhost ~]$ ./mylog.sh
exec test start
[user@localhost ~]$ cat mylog
user tty1 2017-06-22 09:05 (:0)
user pts/0 2017-06-22 09:31 (:0.0)
user pts/1 2017-06-22 09:13 (:0.0)
2017. 06. 22. (목) 09:37:46 KST
exec end
Here Documents 에서 쓰이는 특별한 형태 : <<
- 명령창에서는 '입력이 끝난다는 의미로' crtl+D 키를 사용할 수 있으나 (EOF의미)
- 스크립트(*.sh) 에서는 위 키를 사용할 수 없다. 이를 표현하려면 <<SORTEND 와 같이 사용. 여기서 SORTEND는 다른 문자여도 상관없으며 << 가 사용된다는 것이 중요
<<SORTEND (내용 시작을 의미) ..내용.. SORTEND (내용 끝을 의미, SORTEND 앞에는 절대 공백이나 탭키를 넣지 않음) |
--스크립트 ( 홈폴더 아래에 있는 사용자명을 읽어온 후 각 사용자에게 hello 라는 내용으로 메일쓰기)--
[user@localhost ~]$ cat mail.sh
#!/bin/bash
home=$(ls /home)
for homedir in $home
do
username=$homedir
echo $username
mail -s "here doc test" $username <<MAILEND (mail의 -s 옵션은 제목을 지정함을 의미)
hello
MAILEND <----절대 앞에 탭키를 넣으면안됨
done
--실행결과-------------------------------------
[user@localhost ~]$ ssh test@localhost (test 계정으로 로그인 후 메일 확인)
[test@localhost ~]$ mail
Heirloom Mail version 12.4 7/29/08. Type ? for help.
"/var/spool/mail/test": 4 messages 3 new
1 user Wed Jun 21 10:26 20/629 "hi"
>N 2 user Thu Jun 22 09:38 19/620 "mail test"
N 3 user Thu Jun 22 09:51 17/592
N 4 user Thu Jun 22 09:52 18/615 "here doc test" (메일이 와있음)
&
3장. 정규표현식 - 문자열 패턴을 처리하고자할때 사용하는 표현
^ :한 줄의 시작 $ : 한 줄의 끝 [] : 집합 [^ ] : not 집합 . : 임의의 한 문자 (그냥 점이어도 정규표현식으로 고려될 수 있으므로, 문자열로 표현하고자할땐 \. 으로 표현해야 하는 경우가 있다) |
아래 애들은 앞에 반드시 임의의 어떤 문자( ㅁ으로 표현)가 붙는다. ㅁ* : ex) 호호* : '호호'가 0번이상 매치. 0번 이상이라는 점을 기억하라 => *은 별로 쓰지 않는게 좋다. 정규표현식에서와 다른부분에서 쓰는 의미가 다르므로 실수할수있다. ㅁ+ : 앞에 임의의 문가가 옴. ex) 호호+ : '호호'가 1번이상 매치 ㅁ{n} : 갯수를 정확하게 n번으로 지정 ㅁ{n,} : 갯수를 정확하게 n이상으로 지정 ㅁ{m1,m2} : m1번 이상 m2번 이하 |
|
문자열 패턴을 사용하는 명령어 grep, sed, awk, vi 등에서 문자열 패턴 정의시 정규표현식이 사용가능하다.
4장. grep
한 줄 마다 읽어와서 문자열패턴이 있는지 조사. 일치하면 출력, 일치안하면 버림
$grep 옵션 문자열패턴 대상파일명
옵션
-l (소문자 엘) : 파일명만 추출하고 싶은 경우. 이 옵션이 설정된 경우, 문자열패턴이 포함되어있는 파일이름만 추출 -E : 확장버전의 정규표현식 문자를 쓰고싶을때 -e : 정규표현식쓰고싶을때 -i : 대소문자 무시하고 찾기 -v : 문자열패턴과 일치하지 않는 줄만 출력 |
[user@localhost ~]$ grep user /etc/passwd
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
saslauth:x:498:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin
user:x:500:500:user:/home/user:/bin/bash
- root로 시작하는 줄만 찾고싶을때 - 정규표현식 중 ^을 사용한다
[user@localhost ~]$ grep ^root: /etc/passwd
root:x:0:0:root:/root:/bin/bash
- user로 시작하는 라인만 찾고싶을때
[user@localhost ~]$ grep ^user /etc/passwd
user:x:500:500:user:/home/user:/bin/bash
- bash로 끝나는 줄만 출력
[user@localhost ~]$ grep bash$ /etc/passwd
root:x:0:0:root:/root:/bin/bash
user:x:500:500:user:/home/user:/bin/bash
test:x:501:501::/home/test:/bin/bash
snoopy:x:502:502::/home/snoopy:/bin/bash
-v옵션을 넣으면 조건과 일치하지않는 줄만 출력
[user@localhost ~]$ grep -v bash$ /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
(중략)
- r또는 u로 시작하는 것만찾아라
[user@localhost ~]$ grep ^[ru] /etc/passwd
root:x:0:0:root:/root:/bin/bash
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
rtkit:x:499:497:RealtimeKit:/proc:/sbin/nologin
user:x:500:500:user:/home/user:/bin/bash
- a부터 n 사이 알파벳으로 시작하는 것만 찾아라
[user@localhost ~]$ grep ^[a-n] /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
halt:x:7:0:halt:/sbin:/sbin/halt
(중략)
- a부터 n에 사이에 해당되지않는것. 정규식에서 not을 표현하려면 ^ 이다. 느낌표를 사용하면 안됨
[user@localhost ~]$ grep ^[^a-n] /etc/passwd <---앞의 ^ 는 시작글자를 의미, 뒤에 ^는 not을 표현함을 유의
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
(중략)
- "네자리문자열:" 로 시작하고 두번째 자리가 o 인 행을 출력
[user@localhost ~]$ grep ^.o..: /etc/passwd
root:x:0:0:root:/root:/bin/bash
(유의) 패턴쓸때 홀따옴표 사용하고 역슬래시포함해야함
- o가 연속해서 두번이상나오는패턴
[user@localhost ~]$ grep 'o\{2,\}' /etc/passwd <---- o{2} 로 쓰면 문자로 인식하기 때문에 특수문자앞에 역슬레시 추가 후 홀따옴표로 묶어줌
root:x:0:0:root:/root:/bin/bash
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
snoopy:x:502:502::/home/snoopy:/bin/bash
- o가 한글자라도 들어가있는 것을 출력
[user@localhost ~]$ grep 'o\+' /etc/passwd <-- o+ 로 쓰면 문자로 인식하므로 특수문자 앞에 역슬래시붙이고 홀따옴표로 묶어줌
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
(중략)
- 대소문자구분없이 포함된 줄을 모두 출력하려면 -i 옵션
[user@localhost ~]$ grep -i linux /etc/*.conf
/etc/dnsmasq.conf:# DHCP vendorclass string includes the substring "Linux"
/etc/dnsmasq.conf:#dhcp-vendorclass=red,Linux
/etc/dnsmasq.conf:# Send options to PXELinux. Note that we need to send the options even
/etc/dnsmasq.conf:# See http://syslinux.zytor.com/pxe.php#special for details.
/etc/dnsmasq.conf:#dhcp-option-force=210,/tftpboot/pxelinux/files/
/etc/dnsmasq.conf:#dhcp-boot=pxelinux.0
(중략)
- 파일명만 출력하려면
[user@localhost ~]$ grep -il linux /etc/*.conf <-- 소문자 엘 옵션추가
/etc/dnsmasq.conf
grep: /etc/grub.conf: 허가 거부
grep: /etc/libaudit.conf: 허가 거부
/etc/mtools.conf
(중략)
ps 명령어에 대해 알아보기
- 프로세스 실행자명을 알려면 f 옵션, 내가실행한것뿐만아니라 시스템의 실행중인 모든 프로셋 확인하려면 e 옵션
[user@localhost ~]$ ps -ef | grep crond
root 28223 1 0 02:34 ? 00:00:01 crond
user 33760 32938 0 10:49 pts/1 00:00:00 grep crond
- 위 결과에서 grep crond 만 제외하고 싶다면?
[user@localhost ~]$ ps -ef | grep crond | grep -v grep
root 28223 1 0 02:34 ? 00:00:01 crond
[user@localhost ~]$ ps -ef | grep test
user 33784 33015 0 10:50 pts/0 00:00:00 ssh test@localhost
root 33785 2237 1 10:50 ? 00:00:00 sshd: test [priv]
test 33790 33785 0 10:50 ? 00:00:00 sshd: test@pts/2
test 33791 33790 0 10:50 pts/2 00:00:00 -bash
user 33809 32938 0 10:50 pts/1 00:00:00 grep test
- 위 결과에서 test 계정꺼만 보고싶을때는?
[user@localhost ~]$ ps -ef | grep ^test
test 33790 33785 0 10:50 ? 00:00:00 sshd: test@pts/2
test 33791 33790 0 10:50 pts/2 00:00:00 -bash
sed : 파일을 열지않고 편집하는 도구
한 줄을 읽고 패턴에 해당되는 내용이면 패턴처리후 출력, 패턴에 포함되지않은애들은 그대로 출력
사용방법
(1) 파일명을 입력하는 경우 sed '패턴 명령' 파일명 > 리다일렉트할새로운파일명 -패턴지정시 두가지방법 (1) /문자열패턴/ ex) sed '/문자열패턴/ 명령' 파일명 (2) 줄번호 ex) sed '줄번호 명령' 파일명 <--특정 줄에대해 수행 | 2) 명령어의 수행결과로 편집하는경우 명령어 | sed |
- 명령
s : 교체 ex) s/원본단어/바꿀단어/ <-- 맨뒤에 / 슬러시까지 꼭 붙여야함
d : 삭제
A :
a : \뒤로어펜드
시작라인번호,끝번호
:1,$ s/정규표현식/문자열
중간에 정규표현식을 쓸수있는데, 만약 문자. 을 표현하고자할때는 \. (역슬래시 점을 찍어야한다)
- root로 시작하는 줄이라면 삭제하라
[user@localhost ~]$ sed '/^root/ d' /etc/passwd > noroot
[user@localhost ~]$ head noroot
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
- root로 시작하는 줄이면 그 안에 bash 키워드를 ksh 로 변경하라
[user@localhost ~]$ sed '/^root/ s/bash/ksh/' /etc/passwd >noroot
[user@localhost ~]$ head noroot
root:x:0:0:root:/root:/bin/ksh
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
(중략)
- 맨마지막줄($)에 대해 bash를 ksh로 변경
[user@localhost ~]$ sed '$ s/bash/ksh/' /etc/passwd >noroot
[user@localhost ~]$ tail noroot
ntp:x:38:38::/etc/ntp:/sbin/nologin
apache:x:48:48:Apache:/var/www:/sbin/nologin
saslauth:x:498:76:Saslauthd user:/var/empty/saslauth:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
(중략)
- 첫번째줄에서 마지막줄까지 bash 문자열을 ksh 로 변경
[user@localhost ~]$ sed '1,$ s/bash/ksh/' /etc/passwd >noroot
[user@localhost ~]$ grep bash noroot
[user@localhost ~]$ grep ksh noroot
root:x:0:0:root:/root:/bin/ksh
user:x:500:500:user:/home/user:/bin/ksh
test:x:501:501::/home/test:/bin/ksh
snoopy:x:502:502::/home/snoopy:/bin/ksh
- 현재 디렉토리에 있는 파일에 user를 test 로 바꾸기 (모든 user문자열을 바꾸는게 아니라 처음에 발견한 문자열을 1회에 한하여 변경하는듯하다)
[user@localhost ~]$ ls -l *.sh | sed '1,$ s/user/test/'
-rwxr-xr-x. 1 test user 130 2017-06-22 09:24 array.sh
-rwxr-xr-x. 1 test user 153 2017-06-22 10:21 homecheck.sh
-rwxr-xr-x. 1 test user 343 2017-06-22 11:08 logincheck.sh
-rwxr-xr-x. 1 test user 183 2017-06-22 10:10 mail.sh
-rwxr-xr-x. 1 test user 86 2017-06-22 09:37 mylog.sh
--스크립트 (현재 폴더에 있는 쉘 스크립트의 확장자를 txt 로 변경)
for filename in `echo *.sh`
do
echo $filename | sed '1,$ s/\.sh/.txt/'
done
- 실행결과
[user@localhost ~]$ echo *.sh
array.sh homecheck.sh logincheck.sh mail.sh mylog.sh
[user@localhost ~]$ ./movefile
array.txt
homecheck.txt
logincheck.txt
mail.txt
mylog.txt
awk : 필드단위로 제어가능
파일명 줄단위로 읽어와서 패턴과 일치하면 액션수행
중괄호(액션정의)를 꼭 써야함
sed보다 훨씬 다양하게 패턴정의 가능
awk '패턴정의 {action}' 파일명 -문자열패턴 awk '/문자열패턴/ {실행문}' 파일명 ex) awk '/^root/ {print $0}' /etc/passwd -표현식패턴 awk '표현식 {실행문}' 파일명 ex) awk '$3>=500 {print $1}' /etc/passwd |
패턴정의 방법
/문자열패턴/ |
c&자바에서쓰는 표현식 ==, ><,>=, <= |
앞 ~ 뒤 : 앞에 나온 것이 뒤에 나오는 것에 포함되어있습니까? |
앞 !~ 뒤 : 포함되어있지 않습니까? |
'BEGIN {사전처리} 패턴정의 {action} END {사후처리}' => 괄호안에 연산가능 ex) BEGIN 용도 : 토탈합 구하기 위한 변수초기화, 제목 사전 출력 ex) END 용도 : 작업끝났을때 그 합을 출력 |
액션 정의 방법
if() for while +, -, *, /, % 등 C&JAVA 연산쓸수있고, sin,cos 내장함수도 쓸수있다 (man awk 참조) |
변수사용가능
이중따옴표로 문자열임을 명시해야함 $1>100 $1 == "test" (첫번째 필드 값이 "test" 문자열과 같은지 체크) $1 == test (test를 따옴표로 묶지 않으면 문자열로 인식하지 않음. 변수처리함)
|
리눅스에서 산술연산(소수점까지)이 필요한경우 awk를 사용하면된다.
필드구분자를 별도로 정의하고싶은 경우 -F 옵션 사용
예) :를 구분자로 사용하고싶다면 -F: (띄어쓰기 없이 붙여서 사용)
- root문자열로 시작하는 경우 그 줄을 출력
[user@localhost ~]$ awk '/^root/ { print $0 } ' /etc/passwd
root:x:0:0:root:/root:/bin/bash
-구분자: 를 지정
[user@localhost ~]$ awk -F: '/^root/ { print $0 } ' /etc/passwd
root:x:0:0:root:/root:/bin/bash
-구분자: 를 지정하여 첫번째필드와 여섯번째 필드를 출력
[user@localhost ~]$ awk -F: '/^root/ { print $1, $6 } ' /etc/passwd
root /root
- 세번째필드가 user아이디인데 userid 가 500번 이상인 애들만 출력
[user@localhost ~]$ awk -F: '$3>=500 { print $1, $6 } ' /etc/passwd
user /home/user
test /home/test
snoopy /home/snoopy
-BEGIN, end 패턴
- 맨처음라인에 userlist 문자열 출력, 작업완료후 ==== 문자열 출력
[user@localhost ~]$ awk -F: 'BEGIN { print "userlist" } $3 >= 500 { print $1,$6 } END { print "=======" }' /etc/passwd
userlist
user /home/user
test /home/test
snoopy /home/snoopy
=======
- 작은따옴표안에 있는것을 별도의 파일에 저장해놓고 사용할수있다. (소문자f 옵션 사용)
[user@localhost ~]$ cat user.awk
BEGIN { print "userlist" }
$3 >= 500 { print $1,$6 }
END { print "=======" }
-실행결과
[user@localhost ~]$ awk -F: -f user.awk /etc/passwd
userlist
user /home/user
test /home/test
snoopy /home/snoopy
=======
현재로그인되어있는 사용자의 이름을 알고싶다면? (패턴을 생략하면 전체줄 다 해당된다는 뜻)
[user@localhost ~]$ who | awk '{ print $1 }'
user
user
user
중복된 이름을 쓰고싶다면
[user@localhost ~]$ who | awk '{ print $1 }' | sort | uniq
user
test계정이 새로 로그인했다면
[user@localhost ~]$ who | awk '{ print $1 }' | sort | uniq
test
user
(문제) 현재 로그인되어있는 사용자들에게 write명령을 사용하여 메시지를 보내라
[user@localhost ~]$ cat note
오늘 오후 6시에 수업이 종료됩니다
(문제에대한 답)
#!/bin/bash
users=`who | awk '{ print $1 }' | sort | uniq`
for user in $users
do
write $user <note 2>/dev/null <---write 명령어를 사용함. 입력값은 note에서 가져옴. 오류메시지는 /dev/null처리
done
(문제) 솔라리스에서는 pkill로 프로세스 강제종료한다. 이와 유사하게 프로세스 이름을 입력받아 kill하는 스크립트 작성하기. (단, 내가 사용하는 프로세스만 삭제)
(참고사항)
ps -e <-- 나 말고 다른 사용자들이 수행하는 프로세스까지보는법
ps -ef <-- 누가 이 명령을 수행하고 있는지까지알수있음
(참고사항)
이 쉘을 사용하는 나의 이름을 알아내는 방법
$whoami
$echo $USER
$id -un
(문제에 대한 답)
echo "종료할 프로세스이름"$1
#pid=$(ps -ef | grep $1 | grep -v grep | awk '$1=="user" { print $2 }') <- "user"문자열을 명시적으로 표현 (문자열)
#pid=$(ps -ef | grep $1 | grep -v grep | grep ^$USER | awk '{ print $2 }') <- 사전에 grep으로 분리하는 방법 (변수사용)
pid=$(ps -ef | grep $1 | grep -v grep | awk '$1=="'$USER'" { print $2 }') <- 작은따옴표 분리하는 방법(변수사용)
echo $pid
kill $pid
--실행결과
[user@localhost ~]$ ./killproc.sh sleep
종료됨
[test@localhost ~]$ ps -ef | grep sleep | grep -v grep
user 35461 33015 0 13:48 pts/0 00:00:00 sleep 100
[test@localhost ~]$ ps -ef | grep sleep | grep -v grep | awk '$1==user { print $2 }' (x) - 변수를 이중따옴표로 묶어야한다
[test@localhost ~]$ ps -ef | grep sleep | grep -v grep | awk '$1=="user" { print $2 }' (o)
35461
(참고)
- 로그인할때마다 설정하고 싶을때 (내 설정파일만 적용)
~/.bashrc
~/.bash_profile
- 나 말고 모든 사용자에게 같은 설정을 적용하고싶을땐? (관리자모드에서 아래 파일에 내용 추가)
/etc/profile
awk를 사용하여 소수점연산하기
[user@localhost ~]$ fnum1=10.5
[user@localhost ~]$ fnum2=9.7
- 아래 명령어(let, expr) 들은 소수점 연산을 못한다.
[user@localhost ~]$ expr fnum1 + fun2
expr: non-numeric argument
[user@localhost ~]$ let fsum=fnum1+fnum2
bash: let: 10.5: syntax error: invalid arithmetic operator (error token is ".5")
- awk를 사용한다
[user@localhost ~]$ echo $fnum1 $fnum2 | awk '{ print $1+$2 }' <-- 괄호 안에서 씨언어처럼 사용
20.2
ex) 반 평균 점수구하기
--실행결과
[user@localhost ~]$ cat score.txt
86
74
100
67
89
93
90
[user@localhost ~]$ awk '{ total=total+$1;count++ } END { print total/count }' score.txt <-두개이상의 문장나열시; 세미콜론사용 (씨언어 쓰듯이)
74.875
ex) 로그파일을 사용하여 awk시 ~ 물결 사용하기 (~ 뒷부분은 정규식)
(참고) /var/log/messages 파일내용은 아래와 같음
May 19 14:45:49 localhost kernel: imklog 5.8.10, log source = /proc/kmsg started.
May 19 14:45:49 localhost rsyslogd: [origin software="rsyslogd" swVersion="5.8.10" x-pid="1616" x-info="http://www.rsyslog.com"] start
May 19 14:45:49 localhost kernel: Initializing cgroup subways cpuset
- /var/log/messages 파일에서 세번째필드(시:분:초)정보가 '14:앞자리0~2뒷자리0~9:' 패턴으로 표현되는 라인을 모두 출력하시오.
[root@localhost log]# awk '$3 ~ /14:[0-2][0-9]:/' messages <--- 액션 생략하면 모두 출력
- && 로 묶어서 여러조건 지정가능
[root@localhost log]# awk '$1=="May" && $2=="19" && $3 ~ /14:[0-2][0-9]:/' messages
나와 같은 프로세스를 하나더 만드는 기능 (fork)
- myfork.c ------------------
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
if(fork()==0) { // child process
sleep(3);
system("echo CHILD"); //프로그램안에서 밖에있는 명령어 실행
system("ps -l");
exit (0);
} else { // parent process
sleep(8);
system("echo PARENT");
system("ps -l");
}
return 0;
}
~
"myfork.c" 18L, 326C 저장 했습니다
-컴파일
[user@localhost ~]$ gcc -o myfork myfork.c
-실행결과
[user@localhost ~]$ ./myfork
CHILD
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 500 35495 32913 0 80 0 - 27154 wait pts/2 00:00:00 bash
0 S 500 35835 35495 0 80 0 - 980 hrtime pts/2 00:00:00 myfork (부모 프로세스)
1 S 500 35836 35835 0 80 0 - 980 wait pts/2 00:00:00 myfork (자식프로세스)
0 R 500 35838 35836 0 80 0 - 27033 - pts/2 00:00:00 ps
=> 부모와 자식이 모두 슬립상태(S 상태)
PARENT
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 500 35495 32913 0 80 0 - 27154 wait pts/2 00:00:00 bash
0 S 500 35835 35495 0 80 0 - 980 wait pts/2 00:00:00 my fork (부모 프로세스)
1 Z 500 35836 35835 0 80 0 - 0 exit pts/2 00:00:00 myfork <defunct> (자식프로세스)
0 R 500 35840 35835 0 80 0 - 27033 - pts/2 00:00:00 ps
=> 자식프로세스가 현재 좀비상태(Z 상태) : 자식프로세스가 종료된 시점에 좀비프로세스가 된다. 부모가 얘를 깨끗이 지우기전까지 좀비상태이다
좀비프로세스를 찾아서 그 부모프로세스의 이름을 출력하는 프로그램
(참고)
- 프로세드 상태까지보고싶다면 소문자 엘(l) 옵션 사용
[user@localhost 바탕화면]$ ps -el
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
4 S 0 1 0 0 80 0 - 4839 poll_s ? 00:00:04 init
1 S 0 2 0 0 80 0 - 0 kthrea ? 00:00:00 kthreadd
1 S 0 3 2 0 -40 - - 0 migrat ? 00:00:00 migration/0
1 S 0 4 2 0 80 0 - 0 ksofti ? 00:00:00 ksoftirqd/0
-- 스크립트
[user@localhost ~]$ cat zoombiecheck.sh
#!/bin/bash
# 좀비프로세스를 찾아서 그 부모프로세스의 이름을 출력하는 프로그램
ppid=$(ps -el | awk '$2=="Z" { print $5 }')
echo "zombie의 부모들:"$ppid
for pid in $ppid
do
echo $pid
ps -e | awk '$1=='$pid' { print $4 }'
done
-- 실행결과
[user@localhost ~]$ ./myfork
CHILD
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 500 35854 32913 0 80 0 - 27118 wait pts/1 00:00:00 bash
0 S 500 36020 35854 0 80 0 - 980 hrtime pts/1 00:00:00 myfork
1 S 500 36021 36020 0 80 0 - 980 wait pts/1 00:00:00 myfork
0 R 500 36023 36021 0 80 0 - 27034 - pts/1 00:00:00 ps
PARENT
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 500 35854 32913 0 80 0 - 27118 wait pts/1 00:00:00 bash
0 S 500 36020 35854 0 80 0 - 980 wait pts/1 00:00:00 myfork
1 Z 500 36021 36020 0 80 0 - 0 exit pts/1 00:00:00 myfork <defunct>
0 R 500 36045 36020 0 80 0 - 27033 - pts/1 00:00:00 ps
[user@localhost ~]$ ./yourfork
CHILD
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 500 35495 32913 0 80 0 - 27154 wait pts/2 00:00:00 bash
0 S 500 36016 35495 0 80 0 - 980 hrtime pts/2 00:00:00 yourfork
1 S 500 36017 36016 0 80 0 - 980 wait pts/2 00:00:00 yourfork
0 R 500 36019 36017 0 80 0 - 27034 - pts/2 00:00:00 ps
PARENT
F S UID PID PPID C PRI NI ADDR SZ WCHAN TTY TIME CMD
0 S 500 35495 32913 0 80 0 - 27154 wait pts/2 00:00:00 bash
0 S 500 36016 35495 0 80 0 - 980 wait pts/2 00:00:00 yourfork
1 Z 500 36017 36016 0 80 0 - 0 exit pts/2 00:00:00 yourfork <defunct>
0 R 500 36042 36016 0 80 0 - 27034 - pts/2 00:00:00 ps
[user@localhost ~]$ ./zoombiecheck.sh
yourfork
myfork
fork() 를 호출하면 리턴값으로 자식프로세스의 pid를 전달받는다.
이 함수의 리턴값이 0이면 자식프로세스라는 의미이고, 값이 0이 아니면 자식pid를 전달받은 부모프로세스의 로직이다.
[user@localhost ~]$ cat myfork.c
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
if(fork()==0) { // child process
sleep(3);
system("echo CHILD"); //프로그램안에서 밖에있는 명령어 실행
system("ps -l");
exit (0);
} else { // parent process
//sleep(100);
wait(NULL); <-------- 자식이 종료될때 깨어나라는 의미, sleep대신 이 함수를 사용해도됨
system("echo PARENT");
system("ps -l");
}
return 0;
}
(문제) /var/log 하위 파일들 중 일반파일을 크기순으로 정렬하고, 가장 큰 세개의 파일을 추출하여, 파일 이름과 크기를 추출한다.
(참고) 일반 파일의 크기를 추출하는 법 : ls -l 에서 특정 필드값 추출
(답안)
[user@localhost ~]$ ls -l /var/log | grep ^- | sort -nr -k5 | head -3 | awk 'BEGIN{ print "<filename>\t\t\t<size>"} {print $8, "\t\t\t", $5 }'
<filename> <size>
messages 437841
dracut.log 399323
vmware-tools-upgrader.log 169697
(내가 작성한 답)
[user@localhost ~]$ ls -l /var/log | awk '/^-/ ' | sort -k 5 -r | awk '{ print $5"\t"$8 }' | head -3
437047 messages
399323 dracut.log
169697 vmware-tools-upgrader.log
146876 lastlog
131081 anaconda.syslog
(중략)
(문제) 월,일,시간을 입력받아 /var/log/messages 에 해당하는 시간인 것만 뽑아서 파일로 저장하기 (저장할 파일명:스크립트를 실행한 년월일)
-- 스크립트
[user@localhost ~]$ cat logsearch.sh
#/bin/bash
month=(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
#월 입력
echo "month?(1-12)"
read m
m_month=${month[${m:-6}-1]} <-- 별다른 값이 없으면 1로 디폴드셋팅
echo $m_month
#일 입력
echo "day?"
read d
m_day=${d:-22} <-- 별다른 값이 없으면 22로 디폴드셋팅
echo $m_day
#시 입력
echo "hour?"
read h
m_hour=${h:-00} <-- 별다른 값이 없으면 00로 디폴드셋팅
echo $m_hour
#저장할 파일명은 실행하는 날짜로 하고싶다. "년월일.txt"
filename=`date +%Y%m%d`
#로그파일에서 위에 해당하는 시간인것만 뽑아서 파일에 저장하고싶다
#awk '$1=="'$m_month'" && $2=="'$m_day'" && $3~/"'$m_hour'":[0-5][0-9]:/' /var/log/messages >${filename}.txt (x) <---- $3을 ~ 연산자로 비교시 /문자열/ 정의를 사용함. 변수쓸때는 쌍따옴표를 붙이면안됨. 앞에있는 == 은 뒤에 문자열명시인 ""로 변수를 묶어줘야함
awk '$1=="'$m_month'" && $2=="'$m_day'" && $3~/'$m_hour':[0-4][0-9]/' /var/log/messages >${filename}.txt (o) <---- $3을 ~ 연산자로 비교시 변수에 쌍따옴표를 안붙이는게 맞음
--실행결과
[root@localhost user]# head 20170622.txt
Jun 22 00:08:09 localhost dhclient[35146]: DHCPREQUEST on eth1 to 192.168.11.254 port 67 (xid=0x72c83712)
Jun 22 00:08:09 localhost dhclient[35146]: DHCPACK from 192.168.11.254 (xid=0x72c83712)
Jun 22 00:08:09 localhost dhclient[35146]: bound to 192.168.11.128 -- renewal in 724 seconds.
Jun 22 00:08:09 localhost NetworkManager[1927]: <info> (eth1): DHCPv4 state changed renew -> renew
Jun 22 00:08:09 localhost NetworkManager[1927]: <info> address 192.168.11.128
(중략)
문제 (1) /var/log 디렉토리에서 최근 3일동안 수정되지 않은 일반 파일명과 크기 조사
(참고)find 명령어, 파일의 크기를 알려면 ls -l 사용
find 디렉토리 검색조건:
-name (이름지정)
-mtime 기호n days (수정시각)
ex) -mtime -n 3 (최근 1주일 사이에 수정된 파일)
ex) -mtime +n 3 (최근 1주일 사이에 수정이 안된파일)
-type (파일타입)
ex) -type f (regular 파일을 의미)
-exec (파일을 찾아낸 후 처리할 명령을 옵션으로 같이 줄수있음)
ex) -exec rm {} \; <-- {} \; 란 find로 찾은 파일들을 전달한다는 의미
(정답)
[root@localhost user]# find /var/log -mtime +3 -type f -exec ls -l {} \; | awk ' { print $5"\t" $8} '
0 /var/log/spice-vdagent.log
0 /var/log/wpa_supplicant.log
100933 /var/log/anaconda.yum.log
109901 /var/log/anaconda.storage.log
0 /var/log/spooler
0 /var/log/btmp
7634 /var/log/cups/access_log
41177 /var/log/gdm/:0.log.4
841 /var/log/gdm/:0-greeter.log.4
31 /var/log/gdm/:0-slave.log.4
828 /var/log/gdm/:0-greeter.log.3
(중략)
문제 (2) 현재 수행 중인 프로세스 중 사용자 user가 수행하고 있는 프로세스의 프로세스명(CMD)와 PID조사
[user@localhost ~]$ ps -ef | grep ^user | awk '{print $2"\t"$8}'
2740 /usr/bin/pulseaudio
2747 /usr/libexec/pulse/gconf-helper
32530 /usr/bin/gnome-keyring-daemon
32540 gnome-session
32548 dbus-launch
32549 /bin/dbus-daemon
32569 /usr/libexec/gconfd-2
32576 /usr/libexec/gnome-settings-daemon
32577 seahorse-daemon
(중략)
문제 (3) c프로그램을 컴파일하는 쉘 프로그램을 작성하기. 단, 파일명이 전달되지 않을때에는 현재 디렉토리의 모든 파일을 파일명이 인자로 전달되는 경우에는 해당하는 파일만 컴파일합니다.
-조건
1. 컴파일해야할 파일은 모두 현재 디렉토리에 있는 것으로 간주한다
--스크립트
[user@localhost shell]$ cat compile.sh
#!/bin/bash
cfiles=`ls *.c`
for file in $cfiles
do
echo $file
object=$(echo $file | sed 's/\.c//') <----- sed 문자열패턴에 .c를 공백으로 바꾸는 명령을 주었음. 공백은 //로 표기
# object=${file%*.c}
echo $object
gcc -o $object $file
done
[user@localhost shell]$
--실행결과
[user@localhost shell]$ ls -al
합계 84
drwxrwxr-x. 5 user user 4096 2017-06-22 17:48 .
drwxr-xr-x. 27 user user 4096 2017-06-22 17:40 ..
-rw-------. 1 user user 12288 2017-06-22 17:48 .compile.sh.swp
drwxrwxr-x. 2 user user 4096 2017-06-20 15:44 ch01
drwxrwxr-x. 2 user user 4096 2017-06-22 10:08 ch02
drwxrwxr-x. 2 user user 4096 2017-06-22 16:06 ch03
-rwxr-xr-x. 1 user user 165 2017-06-22 17:48 compile.sh
-rwxrwxr-x. 1 user user 7013 2017-06-22 17:48 myfork
-rw-rw-r--. 1 user user 346 2017-06-22 17:40 myfork.c
-rwxrwxr-x. 1 user user 7014 2017-06-22 17:48 project
-rw-rw-r--. 1 user user 346 2017-06-22 17:40 project.c
-rwxrwxr-x. 1 user user 7013 2017-06-22 17:48 sample
-rw-rw-r--. 1 user user 346 2017-06-22 17:40 sample.c
-rwxrwxr-x. 1 user user 7011 2017-06-22 17:48 test
-rw-rw-r--. 1 user user 346 2017-06-22 17:40 test.c
'Linux_Shell' 카테고리의 다른 글
[쉘프로그래밍] 스트링 앞뒤 공백만 제거 (0) | 2017.08.18 |
---|---|
[쉘프로그래밍] 파일 한줄한줄 읽어와 반복구에 넣기 (0) | 2017.08.17 |
[쉘프로그래밍] Bash Shell Programming (0) | 2017.08.10 |
[쉘프로그래밍] 리눅스 부팅과정, 기본적인 명령어 (0) | 2017.08.10 |
[쉘프로그래밍] 리눅스 개요 (0) | 2017.08.10 |
댓글