2013. 5. 21. 14:01ㆍ99. 정리전 - IT/13. Unix 얇팍지식
출 처 : http://delfa.blog.me
shell, kill, while, for, if
#
# 입력 string을 포함하는 프로세스 죽이기
for pno in `ps | grep $1 | grep -v "grep"`
do
echo $pno
kill -9 $pno
done
#
# 입력한 시간까지 10분 간격으로 명령어 수행하기
if [ "$1" = "" ]; then end="2300"; else end=$1; fi
while :
do
tim=`date +"%H%M"`
echo `date +"%Y-%m-%d %H:%M:%S"`
if [ "$tim" -ge "$end" ]; then
(
cd {directory}
{command1}
{command2}
)
exit
fi
sleep 600
done
shell, kill, while, for, if
#
# 입력된 모든 파일이 생길때까지 sleep
#
# 8초 주기로 완료 여부를 확인하며
# 완료된 목록은 반전으로 보임
#
# 아래와 같이 병렬로 여러개의 프로세스를 수행할때 유용
# for fnm in a b c d e f g
# do
# (
# {command} > result.$fnm.log
# touch $fnm
# ) &
# done
# sleepuntil a b c d e f g
# rm -f a b c d e f g
lst=$*
fnd=""
while [ "$fnd" = "" ]
do
fnd="1"
#
echo " state : \c"
for arg in $lst
do
if [ -f "$arg" ]; then
echo "\033[7m$arg\033[0m \c"
else
echo "$arg \c"
fnd=""
fi
done
echo "\033[K\033[160D\c"
if [ "$fnd" = "" ]; then sleep 8; fi
done
echo "\033[K\c"
sqlplus
#
############################################################
# sqlplus을 통해 출력된 값을 awk 프로그램을 통해 레코드만 출력
# . 변수를 이용하여 동적 query가 가능
# . 본 예는 record 가 2줄에 걸쳐 출력되는 경우임.
(
echo "alter session set nls_date_format='YYYY/MM/DD HH24:MI:SS';"
echo "set feedback off"
echo "set head off"
echo "set linesize 1000"
echo "select a,b,c,d from ... ;"
) | sqlplus <id>/<password> | grep -v "^$" | nawk '
BEGIN { mod=0; }
mod==0&&/^SQL>/ { mod=1; next; }
mod==1&&/^SQL>/ { mod=2; next; }
mod==1 {
if($2=="") printf "%s ",$1; else printf "%s %s %s\n",$1,$2,$3;
next;
}
'
ftp
#
############################################################
# 리모트 서버의 file을 ftp를 통해 가지고 오는 script
# 위와 마찬가지로 변수의 directory나 file을 가져옴
directory="simth"
filename="j.p.smith"
(
echo "user <id> <password>"
if [ "$opt" = "u" ]; then
echo "cd /user/home/$directory"
echo "mget <filename>.log"
else
echo "cd /tmp/log"
echo "get $filename.log"
fi
echo "bye"
) | ftp -ni <ip_address> > /dev/null 2>&1
expr
#
############################################################
# record file에서 값을 가져와 차례로 수행하기
for usr in `cat /etc/passwd | awk -F':' '{ print $1; }'`
do
(
cd ~$usr
du -s .
)
done > diskusage.log
#
# 또는 record가 복잡할 경우
#
lno=1
lns=`head -1 /etc/passwd`
while [ "$lns" != "" ]
do
usr=`expr "$lns" : '\([^:]*\).*$'`
uid=`expr "$lns" : '[^:]*:[^:]*:\([^:]*\).*$'`
# action
echo "$usr's uid = $uid"
#
lno=`expr $lno + 1`
lns=`tail +$lno /etc/passwd | head -1`
done
od, awk
# od 명령어의 -c 와 -x 옵션을 동시에 사용하는 효과
# - HEX 값과 출력이 가능한 ascii 글자를 같은 라인에 출력
# - shell은 다른 unix 명령어들의 제어와 간단한 데이터 처리를 위한 환경이라면,
# awk는 record 형식의 데이터를 처리하는데 목적을 두는 프로그램이다
fnm=$1
if [ "$fnm" = "" ]; then echo "$0 <file_name>"; exit; fi
if [ ! -f "$fnm" ]; then echo "\"$fnm\" not exists"; exit; fi
od -v -x $fnm | nawk '
BEGIN { hex="0123456789abcdef"; }
{
printf "%s ",$0;
for(idx=NF+1;idx<10;idx++) printf " ";
for(idx=2;idx<=NF;idx++){
for(pos=1;pos<=3;pos+=2){
val=((index(hex,substr($idx,pos+0,1))-1)*16)+(index(hex,substr($idx,pos+1,1))-1)
if(val>=32&&val<=127){
printf "%c",val;
}else{
printf ".";
}
}
}
printf "\n";
}
'
# 출력 예
0000000 2321 2f75 7372 2f62 696e 2f73 680a 0a66 #!/usr/bin/sh..f
0000020 6e6d 3d24 310a 6966 205b 2022 2466 6e6d nm=$1.if [ "$fnm
0000040 2220 3d20 2222 205d 3b20 7468 656e 2065 " = "" ]; then e
0000060 6368 6f20 2224 3020 3c66 696c 655f 6e61 cho "$0 <file_na
0000100 6d65 3e22 3b20 6578 6974 3b20 6669 0a69 me>"; exit; fi.i
0000120 6620 5b20 2120 2d66 2022 2466 6e6d 2220 f [ ! -f "$fnm"
0000140 5d3b 2074 6865 6e20 6563 686f 2022 5c22 ]; then echo "\"
0000160 2466 6e6d 5c22 206e 6f74 2065 7869 7374 $fnm\" not exist
nawk, awk
# nawk 프로그램의 다양한 예제입니다.
# nawk는 awk의 확장된 버젼으로 function이 추가 되었고 처리 할 수 있는 record 크기가 큽니다.
##############################
# 기본 구조
# - BEGIN 과 END는 파일 처리 전후에 수행
# - <pattern>
# - 조건이 없을 경우 모든 line 수행
# - 하나의 라인이 여러 조건이 맞을 경우 여러번 처리 될 수 있음 (next; 명령어를 쓰면 다음 레코드 처리 참조)
nawk '
function
BEGIN { <statement;>
<pattern>
<pattern>
END { <statement;>
'
##############################
# shell 과 연동
# - wc 나 ps 등 일부 명령어의 경우 출력시 white space가 앞뒤로 붙는 경우가 있다.
# 단지 값만 원할 경우 유용하게 사용. shell 변수에 white space 가 포함되면 처리하기 귀찮음
lineno=`wc -l
##############################
# shell의 변수 사용하기
# - shell의 변수를 사용하면 더욱 강력한 프로그래밍이 가능
# - [']를 ["]로, ["] 는 [\"]로, [$]를 [\$]로 바꾸고 shell 변수는 [$var] 형식으로 표현
# $var를 단순 대치하는 형식으로 string type으로 쓸경우 \"$var\"로 잘 씌울것~
for fnm in `ls a*`
do
nawk " /$fnm/ { print \"$fnm\",substr(\$6,2,3); } " $fnm
done
##############################
# field 구분
# - nawk,awk의 기본 field 구분은 while space (space,tab)이나 다른 구분자로 구분하고자 할 경우
# - 예 : /etc/passwd file에서 ":"를 구분자로 할경우
nawk -F":" ' {
##############################
# state machine 방식의 처리
# - 정형화 되지 않은 파일이나 pattern이 있을때 유용 (로그 및 result 파일)
# - 아래는 "SQL>"로 시작하는 라인이 있을때까지 라인을 무시하다가
다음 라인 부터 처리. 다시 "SQL>"이 나오면 입력 라인 무시
# - 글 "UNIX Shell 프로그래밍 (sqlplus,ftp,expr)" 참조
nawk '
BEGIN { mod=0; }
mod==0&&/^SQL>/ { mod=1; next; } # next에 의해 아래 부분을 수행하지 않고 다음 라인을 수행
mod==1&&/^SQL>/ { mod=2; next; }
mod==1 { # mod가 1일 경우에만 수행
if($2=="") printf "%s",$1; else printf " %d %s %5.2f\n",int($1*1000),$2,$3;
next;
}
'
statement
##############################
# statement 모음
# - 기본적으로 파일 이외에도 pipe 입력 가능
# - c 언어와 비슷
head -200
# 사용자 function 정의 하기
function myfunction() { #nawk만 지원
<statement;> # 기본적으로 변수는 global로 사용됨
return myvalue; # return 이 없을 경우 일반 procedure...
}
{
# 사용자 function call 하기
val=myfunction();
# "." 이나 " "가 연속으로 있을 경우 newline으로 출력
gsub("[\.][\.]+","\n",str); # nawk만 지원
gsub("[ ][ ]+","\n",str);
printf "%s",str;
# record의 마지막 10개 field를 array에 입력
for(idx=NF-9;idx<=NF;idx++) myarray[idx-(NF-9)]=$(idx);
# "A"에서 "D" 자사이의 string ($0 = 전체 라인)
print substr($0,index($0,"A"),index(substr($0,index($0,"A")),"D")-index($0,"A"));
}
# pattern 의 예 변수 mod가 1이고 첫 field가 "pattern" 일경우
mod==1&&$1=="pattern" { <statement;>
# "pattern"을 포함 할 경우
/pattern/ { <statement;>
# 라인이 "patt"으로 시작하거나 "tern"으로 끝날 경우
/^patt/||/tern$/ { <statement;>
background, grouping
프로그램 또는 프로세스를 background로 실행하려면 명령어의 뒤에
'&' 기호를 이용하면 되는데, telnet 접속을 끊으면 background로
실행되던 프로세스가 같이 죽는 경우가 있다.
이런한 경우에는 shell 프로그램 내에서 원하는 명령어를 background로
실행하게 하고 해당 shell 프로그램을 다시 background로 실행하면
가능한 경우가 있다.
아래는 background 처리를 위한 여러가지 방식의 예를 기술 해 보았다.
예)
. 다음과 같은 mybackground.sh 프로그램이 있을 경우
#!/usr/bin/sh cd $i for myfile in * do ~/bin/myprocess.sh $myfile done # ~ = 로그인 홈 폴더를 의미함 |
. 단순하게 background로 수행
#!/usr/bin/sh
~/bin/mybackground.sh /home/myfolder1 & |
. 별도의 mybackground.sh 프로그램을 쓰지 않고 처리하는 경우
#!/usr/bin/sh ( cd /home/myfolder1 for myfile in * do ~/bin/myprocess.sh $myfile done ) & # 괄호를 빠져나오면 현재 폴더로 다시 돌아옴. # 여러 폴더를 이동하면서 작업하는 프로그램의 경우 유용 |
. 어려 폴더를 동시에 수행하는 경우
#!/usr/bin/sh ~/bin/mybackground.sh /home/myfolder1 & ~/bin/mybackground.sh /home/myfolder2 & ~/bin/mybackground.sh /home/myfolder3 &
# myprocess.sh가 무거울 경우 서버에 많은 부하를 줌 # 빠른 처리가 필요하지 않은 경우 권장하지 않음 |
. 여러 폴더를 차례로 수행하는 경우
#!/usr/bin/sh ( ~/bin/mybackground.sh /home/myfolder1 ~/bin/mybackground.sh /home/myfolder2 ~/bin/mybackground.sh /home/myfolder3 ) &
|
for,sed,awk,grep를 이용하여 property 파일의 값을 일괄 수정하는 예제
java 프로그램을 여러 site에 설치 해야 할 일이 있어 만든 프로그램이다.
아래 프로그램의 예는 shell을 이용하여 java의 properties, xml, ini 파일
등을 일괄적으로 바꿔준다. 일단 어플리케이션 path를 일괄적으로
변경하는 예를 들었지만 같은 방식으로 ip, db 정보등을 변경할 수 있다.
아래 내용을 복사하여 사용 할때 tab(" ") 자와 esacpe code("^[") 주의
-------------------------------------------------------------
#!/usr/bin/sh
############################################
# 파일 명 : changeproperties.sh
############################################
dir=`dirname $0`
cmd=`basename $0`
opt=$1
ag1=$2
err=""
############################################
# default 어플리케이션 object
############################################
ap_home="/usr/home/application"
############################################
# check parameter & environment
############################################
if [ "$opt" = "" ]; then err="1"; fi
if [ "$opt" = "ap_home" ]; then
if [ "$ag1" = "" ]; then ag1="$ap_home"; fi
fi
if [ "$err" = "1" ]; then
# vt100 화면 control 코드 사용. '^['자를 vi에서 입력하려면 <ctrl>-'v'-'['를 치면 됨
echo "^[[1m[ USAGE ]^[[0m"
echo ""
echo " ^[[1m$cmd ap_home <path>^[[0m"
echo " . sets/changes ^[[4mAPPLICATION^[[0m home directory"
echo ""
exit 0
fi
############################################
# process command for ap_home
############################################
if [ "$err" = "" -a "$opt" = "ap_home" ]; then
############################################
# 일반 파일을 변경하는 예
############################################
for fnm in myfile1.ini mufile2.ini
do
# 변경할 대상 파일명을 화면에 출력하는 부분
echo "^[[4mmyfolder1/$fnm^[[0m"
# '[DIRECTORY]' 에 해당하는 값들만 변경하도록 mod 변수 사용
nawk "
BEGIN { mod=1; }
/^\[DIRECTORY]/ { print \$0; mod=0; next; }
mod==0&&/^gen_out/ { print \"gen_out = $ap_home/myfolder1/gen_out/logs/\"; next; }
mod==0&&/^intp_in/ { print \"intp_in = $ap_home/myfolder1/intp_in/logs/\"; next; }
mod==0&&/^sndbak/ { print \"sndbak = $ap_home/myfolder1/sndbak/\"; next; }
mod==0&&/^MA/ { print \"MA = $ap_home/myfolder1/magreement/\"; next; }
mod==0&&/^IA/ { print \"IA = $ap_home/myfolder1/iagreement/\"; next; }
mod==0&&/^BOARD/ { print \"BOARD = $ap_home/myfolder1/work/dir_board/\"; next; }
mod==0&&/^FTP_LOG/ { print \"FTP_LOG = $ap_home/myfolder/work/server_log/\"; next; }
mod==0&&!/^\[/ { print \$0; next; }
/^\[/ { print \$0; mod++; next; }
{ print \$0; }
" myfolder/$fnm > $fnm.tmp
# 변경된 내역을 화면에 출력하는 부분 (앞의 white space를 tab 1개로 변경)
grep $ap_home/myfolder $fnm.tmp | nawk ' { prn=$0; sub("^[ ]*"," ",prn); print prn; }; '
mv $fnm.tmp myfolder/$fnm
done
############################################
# 여러 위치에 있는 jar 파일 내의 환경 파일을 변경하는 경우
############################################
for jnm in myfolder1/myJar1 myfolder1/myJar2 myfolder2/WEB-INF/lib/myJar2
do
# 변경 대상 파일 명을 system.properties 파일에서 먼저 찾음
jar -xf $jnm.jar system.properties
fnm=""
fnm=`sed -e "s/[ ^M]*//g" system.properties | nawk -F= ' /^SettingFileName=/ { print $2; } '`
if [ "$fnm" != "" ]; then
echo "^[[4m$jnm.jar/$fnm^[[0m"
jar -xf $jnm.jar $fnm
nawk "
/^RevIC/ { print \"RevIC=$ap_home/myfolder/intp_in/\"; next; }
/^SndIC/ { print \"SndIC=$ap_home/myfolder/gen_out/\"; next; }
/^Sam/ { print \"Sam=$ap_home/myfolder/sam/\"; next; }
/^Ic/ { print \"Ic=$ap_home/myfolder/ic/\"; next; }
/^Batch/ { print \"Batch=$ap_home/myfolder/batch/\"; next; }
{ print \$0; }
" $fnm > $fnm.tmp
grep $ap_home/myfolder $fnm.tmp | nawk ' { prn=$0; sub("^[ ]*"," ",prn); print prn; };
mv $fnm.tmp $fnm
jar -uf $jnm.jar $fnm
rm -rf system.properties $fnm
fi
done
fi
------------------------------------------------------------
서버 모니터링
아래의 내용을 모니터링 할 수 있는 간단한 shell 스크립트 입니다.
ㅇ CPU 및 메모리 사용율 - 서버의 종합적인 상태
ㅇ 프로세스 수행 개수 - 평균 수에서 변화가 커지면 시스템에 먼가가 일어나고 있음
ㅇ 네트워크 connection 개수 - web 서버나 DB서버 에서 사용자 접속 상태 파악 가능
ㅇ 주요 디스크 사용율 - 로그로 인한 디스크 풀 주의!!
#!/usr/bin/sh # SOLARIS 10 # prtdiag는 root에서만 수행 가능. 일반 user로 수해하려면 값을 명시
logdir=/log/mylog sysmem=`prtdiag | grep "Memory size:" | awk '{ print $3' ; }'` while : do dat=`date +"%y%m%d"` tme=`date +"%y%m%d%H%M"`
# 프로세스 개수 curprc=`ps -e | wc -l | awk ' { print $1; } '`
# 네트워크 connection 수 curnet=`netstat -n | grep ESTABLISHED | wc -l | awk '{ print $1; } '`
# CPU & Memory vmstat 1 2 | tail -1 | awk " { printf \"$tme CPU %d MEM %d PRC $curprc NET $curnet\\n\", 100-\$NF, 100-((\$5/1024)*100/$sysmem); } >> $logdir/svrmon_$dat.log # DISK ( for curdir in /src /log do df -h $curdir | grep "[0-9]G" | grep "[0-9]%" | awk " { print \"$tme DISK $curdir %s\\n\",\$5; } " done ) >> $logdir/dskmon_$dat.log
sleep 60 done
|
위 프로세스를 background로 수행시키고 tail -f /log/mylog/... 명령어로 모니터링 하면 됩니다.
Oracle 모니터링
아래의 내용을 모니터링 할 수 있는 간단한 shell 스크립트 입니다.
ㅇ LOCK 수 - DB가 죽어가는지 확인 가능
아래의 예시를 활용해서 다른 많은 모니터링도 가능하지만 DBA가 아닌
입장에서는 DB와 관련되어 서버 Load, Transaction Load 과 LOCK이 쌓여가는지만 확인하면
보면 충분 한듯합니다. DB 서버 상태는 서버 모니터링에서 Transaction 관련해서는 WAS에서의
Active Data Connection 개수를 모니터링 하면 됩니다.
#!/usr/bin/sh # SOLARIS 10 # Oracle Admin 계정으로 수행 logdir=/log/mylog
while : do dat=`date +"%y%m%d"` tme=`date +"%y%m%d%H%M"`
( echo "select count(distinct(lk.sid)) from v\$lock lk where lk.type in ('TX','TM','UL');" echo "exit" ) | sqlplus "/as sysdba" | awk " BEGIN { mod=0; } mod==0&&/^COUNT.DISTINCT./ { mod=1; next; } mod==1&&/^--------/ { mod=2; next; } mod==2 { printf \"$tme LOCK %d\\n\", \$1; mod=3; next; } " >> $logdir/dbmod_$dat.log
sleep 60 done |
JEUS 모니터링
ㅇ 콘테이너별 사용하는 DataSource Connection 수 - 사용되어지고 있는 DB connection 수
ㅇ 콘테이너별 사용하는 Thread 수 - 처리하고 있는 Transaction 수
어플리케이션 튜닝 상태에 따라 조금 다르겠지만 총 Thread 수는 TPS의 약 10일 수준으로 나타나고
DataSource 수는 Thread 수와 비슷하게 나오는데 이들 정보를 이용하여 콘테이너의 구성 변경 이나
DBMS의 connection resource 및 부하 시 활용 할 수 있습니다.
#!/usr/bin/sh logdir=/log/mylog hostnm=`hostname`
tme=`date +"%y%m%d%H%M"` # ja : jeusadmin # dsinfo : Datasource 정보 # ti : Thread 정보 ( sleep 2 echo "dsinfo -active" sleep 2 echo "ti" sleep 2 echo "exit" ) | ja > $tmp/jeusmon.tmp
# container별, datasource별, active 및 max connection 수 출력 cat $tmp/jeusmon.tmp | /usr/xpg4/bin/grep -e "true" -e "engine container" | /usr/xpg4/bin/awk " /container/ { connme=\$NF; if(\$1==\"Connection\"){ connme=substr(con,12); connme=substr(con,1,length(con)-1); }else{ connme=substr(con,21); connme=substr(con,1,length(con)-1); } connme=toupper(connme); } /true/ { print \"$tme DS=%s ACT=%d MAX=%d\\n\",$connme, \$2, \$8, \$14; } " >> $logdir/jdimon_$dat.log
# container별 active 및 max thread 수 출력 cat $tmp/jeusmon.tmp | /usr/xpg4/bin/grep -e "\[total :" -e "ContainerName" | /usr/xpg4/bin/awk " BEGIN { prenme=\"\"; idlcnt=0; maxcnt=0; } /ContainerName/ { connme=substr(\$4,length(\"$hostnm\")+2); connme=toupper(connme); if(prenme!=\"\"&&prenme!=connme){ printf \"CON=%s ACT=%d MAX=%d\\n\", prenme, maxcnt-idlcnt,maxcnt; idlcnt=0; maxcnt=0; } prenme=connme; } /total :/ { maxcnt=maxcnt+\$3; idlcnt=idlcnt+\$9; } END { printf \"CON=%s ACT=%d MAX=%d\\n\",prenme, maxcnt-idlcnt,maxcnt; } " >> $logdir/jtimon_$dat.log
sleep 60 done |
거래 내용을 모니터링하려면 APM 이나 DB 모니터링 툴이 있어야 하겠죠?
그리고 모니터링 관련 글에서 내용들을 tail -f 로 보려면 전체 현황 파악이 힘듭니다.
nmon이나 top 명령어처럼 전체 상황들을 dashboard 처럼 한 화면 내에서 모니터링 대상 서버별로
모니터링 항목들이 표처럼 출력 할 필요가 있습니다.