블로그 이미지
OSSW(Open Source System SoftWare

calendar

            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            

Notice

#!/bin/bash


outDir=/home/NETSTAT


if [ ! -d ${outDir} ]; then       // outDir 변수로 지정한 디렉토리가 존재하지 않을 경우, 디렉토리를 생성한다.

mkdir -p ${outDir}

fi


idx=1


outFile=${outDir}/netstat_`hostname`_`date +%y%m%d`.log


if [ ! -f ${outFile} ]; then       // outFile 변수로 지정한 파일이 존재하지 않을 경우, 컬럼명을 탭 간격을 주고 outFile 에 프린팅한다.

printf "CLOSED\\tCLOSING\\tCLOSE_WAIT\\tESTABLISHED\\tFIN_WAIT1\\tFIN_WAIT2\\tLAST_ACK\\tLISTEN\\tSYN_SENT\\tSYN_RECEIVED\\tTIME_WAIT\\n" > ${outFile}

fi


while [ 1 ]; do


CLOSED=0

CLOSING=0

CLOSE_WAIT=0

ESTABLISHED=0

FIN_WAIT1=0

FIN_WAIT2=0

LAST_ACK=0

LISTEN=0

SYN_SENT=0

SYN_RECEIVED=0

TIME_WAIT=0           // netstat 상태값들을 기본 0 으로 모두 초기화

netState=`netstat -na | grep tcp | awk '{print $6}' | sort | uniq -c`    // 이 명령에 의해 뿌려지는 값들을 


* netstat 명령 수행 결과 예시

# netstat -na | grep tcp | awk '{print $6}' | sort | uniq -c

      1 CLOSE_WAIT

     31 CLOSING

    234 ESTABLISHED

     15 FIN_WAIT1

     59 FIN_WAIT2

     21 LAST_ACK

     10 LISTEN

     33 SYN_RECV

   1109 TIME_WAIT

--> 첫 번째 열은 명령 수행 시점의 netstat 상태값의 개수, 두 번째 열은 netstat 상태값


for tmp in ${netState} ; do        // 하나씩 tmp 변수에 담아

remNum=`expr ${idx} % 2`      // idx 변수값을 2로 나눈 나머지(remNum)가

if [ ${remNum} -ne 0 ]; then      // 0 이 아니면(for문이 홀수번째로 수행된 거라면.. 즉, netstat 상태값의 개수가 tmp 변수에 넘어온 거라면)

sockNum=${tmp}              // netstat 상태값의 개수를 sockNum 변수에 담고

else          // 그렇지 않으면(for문이 짝수번째로 수행된 거라면.. 즉, netstat 상태값이 tmp 변수에 넘어온 거라면)

state=${tmp}                   // netstat 상태값을 state 변수에 담고

case ${state} in               // state 변수의 값에 따라 앞서 홀수번째에 세팅되었던 sockNum 값을 각 상태값에 맞게 할당

"CLOSED")

CLOSED=${sockNum}

;;

"CLOSING")

CLOSING=${sockNum}

;;

"CLOSE_WAIT")

CLOSE_WAIT=${sockNum}

;;

"ESTABLISHED")

ESTABLISHED=${sockNum}

;;

"FIN_WAIT1")

FIN_WAIT1=${sockNum}

;;

"FIN_WAIT2")

FIN_WAIT2=${sockNum}

;;

"LAST_ACK")

LAST_ACK=${sockNum}

;;

"LISTEN")

LISTEN=${sockNum}

;;

"SYN_SENT")

SYN_SENT=${sockNum}

;;

"SYN_RECEIVED")

SYN_RECEIVED=${sockNum}

;;

"TIME_WAIT")

TIME_WAIT=${sockNum}

;;

esac

fi

idx=$((idx+1))

done


printf "${CLOSED}\\t${CLOSING}\\t${CLOSE_WAIT}\\t\\t${ESTABLISHED}\\t\\t${FIN_WAIT1}\\t\\t${FIN_WAIT2}\\t\\t${LAST_ACK}\\t\\t${LISTEN}\\t${SYN_SENT}\\t\\t${SYN_RECEIVED}\\t\\t${TIME_WAIT}\\n" >> ${outFile}         // while 문의 결과에 따라 할당된 변수들을 outFile 에 프린트


sleep 10

done


위와 같이 Shell Script 를 작성한 후, crontab에 아래와 같이 설정합니다.

# crontab -l

* * * * * /home/mon_netstat.sh >& /dev/null


감사합니다.


posted by 박현명

시스템에 할당되어 있는 PCI Slot의 사용내역을 확인하는 스크립트 입니다.

 

SLot별로 어떤 Device가 연결되어 있는지 직관적으로 파악이 가능합니다.

 

 

1. 스크립트 (slot.sh)

-----------------------------------------------------------------

#!/bin/sh

 

cnt=1

 

NET_DIR="/sys/class/net"

DISK_DIR="/sys/class/scsi_disk"

TAPE_DIR="/sys/class/scsi_tape"

 

clear

echo "#######################################"

echo -n "HOSTNAME :"

hostname

dmidecode | grep "Product Name"

echo "#######################################"

 

for i in `dmidecode | grep Bus | grep -v Type | sed -e 's/0000://' | sed -e 's/\.0//' | awk '{print $3}'`

do

    BUS=`lspci | grep $i`

    echo ">> Slot"$cnt " " $BUS

 

    ls -al $NET_DIR | grep $i | awk '{print " " $9}'

    ls -al $DISK_DIR | grep $i | awk '{print " " $9}'

    ls -al $TAPE_DIR | grep $i | awk '{print " " $9}' | grep nst

 

    cnt=$(($cnt+1))

done

------------------------------------------------------------------

 

 

2. 수행결과

 

 

 

#######################################

HOSTNAME :OOO DB1

Product Name: ProLiant DL380p Gen8

#######################################

>> Slot1 04:00.0 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01) 04:00.1 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01)

eth8

eth9

>> Slot2 07:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01) 07:00.1 Ethernet controller: Intel Corporation I350 Gigabit N etwork Connection (rev 01)

eth0

eth1

>> Slot3 0a:00.0 Fibre Channel: Emulex Corporation Saturn-X: LightPulse Fibre Channel Host Adapter (rev 03) 0a:00.1 Fibre Channel: Emulex Corporation Saturn-X : LightPulse Fibre Channel Host Adapter (rev 03)

nst0

nst1

nst2

nst3

nst4

>> Slot4 21:00.0 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01) 21:00.1 Ethernet controller: Intel Corporation 82599EB 10-Gigabit SFI/SFP+ Network Connection (rev 01)

eth10

eth11

>> Slot5 24:00.0 Ethernet controller: Intel Corporation I350 Gigabit Network Connection (rev 01) 24:00.1 Ethernet controller: Intel Corporation I350 Gigabit N etwork Connection (rev 01)

eth2

eth3

>> Slot6 27:00.0 Fibre Channel: Emulex Corporation Saturn-X: LightPulse Fibre Channel Host Adapter (rev 03) 27:00.1 Fibre Channel: Emulex Corporation Saturn-X : LightPulse Fibre Channel Host Adapter (rev 03)

nst5

nst6

nst7

nst8

nst9

>> Slot7 03:00.0 Ethernet controller: Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01) 03:00.1 Ethernet controller: Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01) 03:00.2 Ethernet controller: Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01) 03:00.3 Ethe rnet controller: Broadcom Corporation NetXtreme BCM5719 Gigabit Ethernet PCIe (rev 01)

eth4

eth5

eth6

eth7

>> Slot8 02:00.0 RAID bus controller: Hewlett-Packard Company Device 323b (rev 01)

 

 

 

by 이찬호

posted by DB,MW,OS OSSW(Open Source System SoftWare


check_filesize.sh

이전 글에 이어 특정 파일시스템에서 어떤 파일들이 용량을 많이 차지하고 있는지 확인하는 스크립트에 대해 글 올립니다.

먼저 스크립트 전문은 다음과 같습니다.

#!/bin/bash


SEARCH_PATH=${1}        // 특정 용량 이상을 차지하는 file 들을 확인할 디렉토리명

MB_SIZE=${2}                // 어느 정도 용량 이상의 file 들을 확인할 것인지 MB 단위로 지정


cd ${SEARCH_PATH}


### Check File Size more than ${MB_SIZEMB

file_list=`find . -size +${MB_SIZE}M -type f -print`    // ${MB_SIZE} MB 이상의 type 이 file인 것들을 ${SEARCH_PATH} 에서 find 하여 파일명만 file_list 변수에 저장


if [ $? -eq 0 ]; then        // 위 명령이 정상 수행되었다면(return code: 0),


for file in ${file_list}; do        // 파일 리스트들을 하나씩 받아서

ls -l ${file}                    // ls 명령으로 ownership, permission, file size 등을 확인

done

else

echo 'The running of shell command is failed!!'    // find 명령이 정상 수행되지 않았다면, 에러 메시지를 뿌리고 스크립트 종료

exit

fi


위 스크립트 구문은 사실 find 의 옵션 하나만 알고 있다면 다음과 같이 줄일 수 있습니다.

#!/bin/bash


SEARCH_PATH=${1}

MB_SIZE=${2}


cd ${SEARCH_PATH}


### Check File Size more than ${MB_SIZEMB

find . -size +${MB_SIZE}M -type f -exec ls -l {} \;


if [ $? -ne 0 ]; then

        echo 'The running of shell command is failed!!'    // find 명령이 정상 수행되지 않았다면, 에러 메시지를 뿌리고 스크립트 종료

        exit

fi


전후 스크립트의 차이점이라면, find 명령에 exec 옵션을 사용하여 그 아래에 있던 if문과 for문을 없애버린 점인데요.

exec 옵션은 find 명령을 통해 찾은 결과값들을 대상으로 exec 옵션 뒤의 명령들을 수행하겠다는 옵션입니다.

위 예제에서는 ${MB_SIZE} MB 이상 되는 file 들을 찾아서 ls -l 명령을 수행하겠다는 뜻이 되겠죠.

exec 옵션 뒤의 {} 와 \; 의 의미는 다음과 같습니다.

{} : find 에서 찾아낸 검색 결과가 하나씩 들어가는 부분(for문과 같은 역할)

\; : -exec 옵션 다음에 나오는 명령어를 실행


위 주석을 참조하여 스크립트를 이해하시면 되겠고, 원본 스크립트는 파일로 첨부하였습니다.

감사합니다.

posted by 박현명

linux에서 시스템 전체 파일시스템의 용량 및 사용량 확인 스크립트     

 

------------------------------------------------------------------------------------------------------

#!/bin/sh

 

 

df -k | awk 'BEGIN { Total_Size=0; Total_Used=0; Total_Avail=0 } { Total_Size += $2; Total_Used += $3 ; Total_Avail += $4 } END { printf("Total Size : %5.1f GB, Total Used : %5.1f GB, Total_Avail : %5.1f GB, Used % : %5.1f %\n", Total_Size/1024/1024, Total_Used/1024/1024, Total_Avail/1024/1024, Total_Used/Total_Size*100) }'

------------------------------------------------------------------------------------------------------

 

< 결과 >

$ df -k

Filesystem 1K-blocks Used Available Use% Mounted on

/dev/xvda3  20642428 659376 18934476 4% /

tmpfs          10194012 0 10194012 0% /dev/shm

/dev/xvda1 1032088 79052 900608 9% /boot

/dev/xvda2 30963708 16381900 13008944 56% /home

/dev/xvda5 20642428 1653392 17940460 9% /usr

/dev/xvda6 20642428 515020 19078832 3% /var

/dev/xvdb1 1028100912 429494932 546381480 45% /app

/dev/xvdc1 516054864 52777072 437063732 11% /data

 

$ df -k | awk 'BEGIN { Total_Size=0; Total_Used=0; Total_Avail=0 } { Total_Size += $2; Total_Used += $3 ; Total_Avail += $4 } END { printf("Total Size : %5.1f GB, Total Used : %5.1f GB, Total_Avail : %5.1f GB, Used % : %5.1f %\n", Total_Size/1024/1024, Total_Used/1024/1024, Total_Avail/1024/1024, Total_Used/Total_Size*100) }'

 

Total Size : 1571.9 GB, Total Used : 478.3 GB, Total_Avail : 1014.2 GB, Used % : 30.4 %

 

 

 

by 이찬호

posted by DB,MW,OS OSSW(Open Source System SoftWare


check_filesystem_usage.sh

파일시스템 사용량 체크를 간편하게 하기 위한 스크립트에 대해 글 올립니다.

Linux 에서 파일시스템 사용량을 점검하는 것이 매우 중요하다는 것은 다 알고 계실 겁니다.

점검해야 할 서버 대수가 적고 별다른 할 일이 없을 만큼 한가하다면 일일이 육안으로 점검해도 되겠지만, 

점검해야 할 대상 서버와 파일시스템이 많다면 일일이 점검하다가 눈이 골뱅이가 될 것입니다.(@.@)

이럴 때 편하게 점검할 수 있는 스크립트입니다.

#!/bin/bash

threshold=${1}                         // 스크립트 실행 시의 input parameter를 threshold 변수에 저장

fs_use_lists=`df -Ph | grep -v Filesystem | awk '{print $6,$5}'`

                                                 // df 명령을 통해 파일시스템명과 사용률(Use%) 추출

idx=1

for tmp in ${fs_use_lists}; do

 // 파일시스템과 사용률 리스트를 받아 for문을 돌리는데, {파일시스템1}, {사용률1}, {파일시스템2}, {사용률2}, ... 와 같은 식으로 tmp 변수에 input 되므로,

remNum=`expr ${idx} % 2`   // remNum 이란 변수에 idx 변수값을 2로 나눈 나머지값을 넣어

if [ ${remNum} -ne 0 ]; then   // remNum 변수가 '0'이 아니면(즉, for문이 홀수번째로 돌면)

fs_name=${tmp}      // for문이 홀수번째 돌 때, tmp에 들어오는 값은 파일시스템명이고,

else         // 그렇지 않고 remNum 변수가 '0'이면(즉, for문이 짝수번째로 돌면)

usage=`echo ${tmp} | cut -d ' ' -f 2 | cut -d '%' -f 1`

                      // tmp에 들어오는 값은 사용률(Use%) 이므로 계산을 위해 공백과 % 기호를 제거한 후,

                         usage 변수에 저장

if [ ${usage} -gt ${threshold} ]; then      // threshold 값보다 usage 값이 크면,

echo 'The '${fs_name}' filesystem is using '${usage}'% and exceeded threshold!!'              // 파일시스템 사용률이 임계치를 초과했다는 코멘트를 print

fi

fi

idx=$((idx+1))     // fs_use_lists 값이 전부 처리될 때까지 idx 값을 1씩 증가시켜 for문 수행

done


상세 내역은 위의 주석 부분을 참조하시면 되고 원본 스크립트는 파일로 첨부하였습니다.

위와 같이 파일시스템 사용량을 체크했다면, 해당 파일시스템에서 대체 어떤 파일들이 공간을 많이 차지하고 있는지 궁금해지겠죠?

특정 파일시스템에서 일정 크기 이상 가진 파일들을 list-up 하는 스크립트는 다음 글에서 설명 드리겠습니다.

감사합니다.


posted by 박현명

Linux 사용하시다가 history 명령어 많이 사용 하시죠?

 

그런데, 불편한게 날짜가 없어서 보기가 참 애매 했었는데요.

 

history에 날짜를 넣는 방법이 있어 알려 드립니다.

 

1. bash 쉘 사용자

 

2. /etc/bashrc 파일 확인

 

3. /etc/bashrc 파일 마지막 라인에 아래 사항 추가

 

  추가) export HISTIMEFORMAT="[%Y-%m-%d %H:%M:%S]"

 

4. 다움 세션 로그인 부터 적용됨

 

예)

[2014-05-23 11:25:34] ls -rlt

[2014-05-23 11:25:46] df -k

[2014-05-23 11:25:58] ps -ef

 

참고로 날짜 포맷을 다양하게 원하는 스타일로 셋팅 하시면 됩니다.

 

posted by 허시영

posted by DB,MW,OS OSSW(Open Source System SoftWare

SSH(Secrure SHell) 의 패스워드 입력없이 사용 하기

 

1. 로컬 서버에서 아래 실행 해서 public key 생성

   $ ssh-keygen -t dsa

위명령어 실행하면, 계정 홈디렉토리의 .ssh 디렉토리가 생기고, id_dsa.pub 생성됨.

 

2. 접속할(target) 리모트 서버에서, sftp 로 로그인할 계정의 홈디렉토리 생성

  $ mkdir ~/.ssh

 .ssh 의 디렉토리 권한은(660) 이어야 함.

 

3. 로컬서버에서 아래 실행

  $ scp ~/.ssh/id_dsa.pub user@SERVER:.ssh/authorized_keys

  위명령어 실행시 최초에는 패스워드를 입력하고, 그후에는 패스워드 없이 사용가능

  리모트 서버에서 ~/.ssh 에 authorized_keys 파일 생성 확인

 

4. 이러면 패스워드 없이 scp 및 sftp 사용 세팅 끝

 

5. 스크립트를 이용한 sftp 이용하기

 

#!/bin/sh

 

REMOTE_FTP_ADDR="리모트서버 IP"

REMOTE_USER="로그인할 계정"

REMOTE_UPLOAD_PATH='리모트 디렉토리 위치"

LOCAL_UPLOAD_PATH="로컬 디렉토리 위치"

 

sftp $REMOTE_USER@REMOTE__FTP_ADDR << EOF

 

cd $REMOTE_UPLOAD_PATH

lcd $LOCAL_UPLOAD_PATH

put $1

quit

EOF

 

** 단 이기종 간에 선작업으로 SSH 22 번 port 를 열어주는 방화벽작업이 선행 되어야 함 **

 

 

write by 허시영

posted by DB,MW,OS OSSW(Open Source System SoftWare

#!/bin/sh

DISK=`cat /etc/sysconfig/rawdevices | grep -v \# | awk -F /dev/ '{print $3}'`

for i in $DISK

do

SIZE=`cat /proc/partitions | grep $i | awk '{print $3}'`

echo $i $(($SIZE/1024/1024)) GB

done

 

 

-- by 이찬호

posted by DB,MW,OS OSSW(Open Source System SoftWare

이번 글에서는 expect 스크립트에 대한 예제를 통해 이해를 돕는 시간을 갖도록 하겠습니다.

 

(2) 예제


#!/bin/expect


set target "[lindex $argv 0]"
set rootid "[lindex $argv 1]"
set oldpwd "[lindex $argv 2]"
set newpwd "[lindex $argv 3]"
spawn telnet $target
expect -timeout 5 "*ogin:"
send "$rootid\n"
expect -timeout 5 "*assword:"
send "$oldpwd\n"
sleep 2
expect -timeout 5 "#|>"
send "passwd\n"
expect -timeout 5 "New password:"
send "$newpwd\n"
expect -timeout 5 "Re-enter root's new password:"
send "$newpwd\n"

expect eof


    a. 내부변수 선언 및 외부변수 세팅

#!/bin/expect


set target "[lindex $argv 0]"
set rootid "[lindex $argv 1]"
set oldpwd "[lindex $argv 2]"

set newpwd "[lindex $argv 3]"


set 명령은 내부변수를 선언하기 위한 명령어입니다.

 

set target [변수값] 이라고 하면 target 이란 변수를 생성하여 '변수값'을 할당하겠다는 뜻이지요.

 

변수값 자리에 문자열이나 숫자같은 고정값을 하드코딩해 주어도 되지만, 여기서는 외부로부터 입력 변수를 받아 처리하기 위해 "[lindex $argv 0]" 이란 값을 사용했습니다.

 

외부변수로 입력된 값중에 제일 첫번째 값을 가져다가 target 변수에 세팅하겠다는 것입니다.

 

rootid, oldpwd, newpwd 등도 외부변수로 입력된 값중에 각각 두번째, 세번째, 네번째 값을 가져다가 세팅하게 됩니다.

 

    b. 실행 서비스 설정


spawn telnet $target


spawn 명령을 통하여 target 시스템에 접근할 서비스를 telnet 으로 세팅합니다.

 

target 변수에는 IP address 혹은 /etc/hosts 파일에 도메인 세팅이 되어 있는 경우 hostname이 들어오게 되겠죠.

 

    c. 패스워드 변경 수행


expect -timeout 5 "*ogin:"                                     // '*ogin:' 문자열이 뜨기를 5초간 기다림
send "$rootid\n"                                                    // rootid 변수에 할당된 값을 보내고 엔터(\n)를 누름
expect -timeout 5 "*assword:"                              // '*assword:' 문자열이 뜨기를 5초간 기다림
send "$oldpwd\n"                                                  // oldpwd 변수에 할당된 값을 보내고 엔터(\n)를 누름
sleep 2                                                                  // 2초간 waiting
expect -timeout 5 "#|>"                                        // '#'이나 '>' 문자열이 뜨기를 5초간 기다림
send "passwd\n"                                                   // passwd 명령을 보내고 엔터(\n)를 누름
expect -timeout 5 "New password:"
send "$newpwd\n"
expect -timeout 5 "Re-enter root's new password:"

send "$newpwd\n"



expect 명령을 사용하여 'ogin:' 으로 끝나는 문자열을 기다립니다.

 

시스템마다 로그인하려 할 때, 소문자로 'login:' 이 뜨는 경우도 있고 대문자로 'Login:' 이 뜨는 경우도 있어 제일 앞을 '*(asterisk)' 로 처리했습니다.

 

-timeout 5 옵션은 '*ogin:' 이란 문자열이 뜨기를 5초동안 기다리겠다는 것입니다.

 

네트워크의 성능에 따라 시스템에 접속할 때 로그인 프롬프트가 뜨는 시간이 조금씩 다르기 때문에 최소 5초 정도의 여유를 주는 것이 좋습니다.

 

5초 이후에도 해당 문자열이 뜨지 않으면 다음에 나오는 send 명령을 그냥 수행시켜 버립니다.

 

expect -timeout 5 "#|>" 명령 구문은 로그인 후에 해당 시스템의 프롬프트가 떨어지길 기다리고, 그 프롬프트의 제일 마지막 문자열이 '#' 이나 '>' 이길 기다립니다.

 

예제에서는 '#' 과 '>' 만 나열하였지만, 혹시나 프롬프트에 '$' 나 ']' 와 같은 다른 문자열이 마지막에 들어가 있다면 이러한 문자열들도 expect 명령 구문에 포함시켜야 합니다.

 

    d. expect 스크립트 종료 선언


expect eof



expect eof 명령 구문을 사용하여 expect 스크립트를 명시적으로 종료합니다.

 

해당 구문을 사용하지 않을 경우, 스크립트가 정상 종료하지 않은 상태로 남아있게 되어 Ctrl + c 명령 등을 통해 강제 종료해야 합니다.

 

이렇게 expect 스크립트를 모두 작성하였다면 이제 실행해야겠죠?

 

    e. expect 실행


./aix_change_pwd.exp 192.168.63.1 root root password



expect 스크립트의 확장자는 .exp 로 하시면 됩니다.

 

위와 같이 input 변수를 주고 실행한다면 192.168.63.1 IP를 가진 시스템에 root 계정으로 접근하여 기존 패스워드인 root 를 password 로 바꾸게 됩니다.

 

막상 알고보면 별거 없는데 제가 말주변이 없어서 설명을 좀 어렵게 적어놓은 듯 싶네요..;;;;

 

아주 기본적인 예제에 대해서만 설명해 놓았으나, expect 스크립트에도 bash 나 ksh 처럼 if문이나 for문 등을 사용할 수 있습니다.

posted by 박현명

이번 글에서는 자동화를 위해 유용하게 사용할 수 있는 expect 란 스크립트에 대해서 말씀 드리도록 하겠습니다.

 

expect 는 telnet이나 ftp와 같이 interactive한 환경이 필요한 곳에서 특정 문자열을 기다리고(expect), 정해진 문자열을 자동으로 보내는(send) 등의 처리를 하는 스크립트 언어입니다.

 

가령, A라는 서버에서 B라는 서버의 패스워드를 바꾸려 한다고 하면, telnet을 이용하여 B서버로 로그인하고 password 명령을 이용해 기존 패스워드와 새로운 패스워드를 차례로 입력하는 일련의 과정들을 거치게 됩니다.

 

하지만, 이 expect 를 이용하면 그런 절차들을 일일이 거칠 필요 없이 스크립트 하나만 돌림으로써 문제를 해결할 수 있습니다.

 

expect 스크립트를 사용하려면 bash나 ssh 등 여타 서비스들과 마찬가지로 시스템 상에 expect 모듈이 설치되어 있어야 하며, expect 설치 시에는 tcl과 tk 라는 두 가지 의존성을 가진 모듈이 함께 필요합니다.


(1) 기본 사용법

 

    a. 스크립트 선언


#!/bin/expect


bash나 ksh 등의 shell script 를 수행하기 위해서도 스크립트문 안에 위와 같이 선언을 해줘야 하듯, expect도 같은 방식으로 선언해 주어야 합니다.

 

expect 의 설치 위치가 bin 디렉토리 밑이 아니라면 bin 디렉토리 아래로 심볼릭 링크를 해주어야 합니다.

 

    b. target 시스템 설정


set target 192.168.63.1


해당 expect 스크립트를 수행할 target 시스템을 설정하는 부분입니다.

 

    c. 실행할 서비스 설정


spawn telnet $target



어떤 서비스를 이용하여 target 시스템에 접근할 것인지를 설정하는 부분으로, spawn 명령은 상호대화(interactive)할 프로그램을 띄우기 위한 목적으로 사용합니다.

 

    d. 예상되는 문구 설정


expect [-re] 예상문구                 // ex. expect -re "login:"



위에 나열한 순서로 target 시스템에 telnet 접근했을 때, 제일 먼저 뜨는 것은 ' login: ' 이라는 문구일 것입니다.

 

그러한 경우에 옆에 주석으로 달아놓은 것처럼 expect -re "login:" 이라고 설정하면 됩니다.

 

-re 옵션은 정규 표현식(regular expression)을 위해 사용합니다.

 

가령, expect -re "a*" 라고 설정하였다면, a, aa, aaa, aaaa, ... 등의 문자열과는 매치(match)하지만 ab, ac 등의 문자열과는 매치하지 않고,

 

expect "a*" 라고 설정하였다면, aa, ab, ac 등과 같은 문자열과 매치합니다.

 

    e. 원하는 값 보내기


send 원하는 값                           // ex. send "root"



예상되는 문구가 정상적으로 스크립트에서 인지되었다면 인제 그에 맞는 값을 target 시스템에 던져야겠죠?

 

target 시스템에 root로 로그인하고자 한다면 위와 같이 send "root" 라고 설정하면 됩니다.

 

    f. delay time 설정


sleep 자연수



시스템마다 조금씩 차이가 있는 것이 telnet을 이용하여 시스템에 접속하고 login 계정을 입력한 후 엔터를 치면, password 입력 프롬프트가 바로 안 나오고 1~2초 후에 보이는 경우가 있습니다.

 

그런 시스템에서 이 sleep 명령을 주지 않고 expect 다음에 send 명령을 바로 사용하면 멍~ 때리는 현상이 발생하게 됩니다.

 

예상되는 문구가 뜨기도 전에 target 시스템에 문자열을 날려 버리기 때문이지요.

 

expect 라는 자동화 스크립트의 특성상 한번 그렇게 문자열이 앞당겨져서 날라가게 되면 다음에 나오는 명령들도 줄줄이 앞당겨져서, 예상문구를 기다리지도 않고 날라가게 됩니다.

 

그러면 스크립트가 더 이상 수행되지 않고 멍 때리는 현상이 발생하지요.

 

그러므로 expect 스크립트에선 어떤 시스템에도 종속되지 않게 sleep 을 잘 사용하여 표준화하는 것이 중요합니다.

 

이러한 expect 스크립트에 대한 자료는 구글링을 아무리 해도 많지 않기에 expect 스크립트를 사용하시려는 분들께 도움이 되었으면 합니다.

 

다음 글에서는 예제를 통해 더 자세히 살펴보도록 하겠습니다.

posted by 박현명

지난 글에 이어서 이번에는 sed를 이용하여 new line을 특정 문자열로 변경하는 방법에 대해 말씀 드리도록 하겠습니다.

 

(2) new line --> 특정 문자열


# cat test.txt

11111

22222

33333

44444

55555



위와 같은 컨텐츠를 가진 txt 파일이 있다고 가정합니다.

 

위 컨텐츠에서 Enter가 적용된 부분(new line)을 ':'(colon)으로 변경하고자 한다면 다음과 같이 수행합니다.


# sed 'N;N;N;N;s/\n/:/g' test.txt



sed 명령에서 'N' 옵션은 줄바꿈문자(\n)를 /A패턴/ 공간에 더하고 입력의 다음 줄을 읽어 패턴 스페이스에 덧붙이겠다는 뜻입니다.

 

무슨 말인지 이해가 잘 되시나요?

 

사실 저는 아직도 완전히 이해가 되지는 않습니다.;;;;

 

문제 해결방안을 찾다보니 아래와 같이 한글로 된 URL을 찾았는데 그 글을 올리신 분이 정의해 놓은 것을 그냥 가져다 적은 것입니다.

(출처: http://wiki.kldp.org/Translations/html/Sed-KLDP/sedprograms.html#OVERVIEWOFREGULAREXPRESSIONSYNTAX)

 

아무튼 특정 문자열로 변경해야할 new line의 수만큼 'N' 옵션을 써주시면 되는데요.

 

이 옵션 사용 후 /A패턴/ 에 해당하는 부분에 개행문자인 '\n' 을 입력해 주시고 /B패턴/ 에 new line 대신 들어갈 문자열을 입력해 주시면 됩니다.

 

이렇게 하는 것이 제가 sed를 이용해서 new line을 특정 문자열로 변경하는 방법이라고 알아낸 것인데요.

 

한 가지 단점이..

 

위와 같은 예제에서 new line의 개수가 정확히 몇 개인지 확인이 가능하다면 모르겠지만, 개수 파악이 안되는 컨텐츠의 경우 어떻게 해야 할지 아직 찾지 못했습니다.;;;;

 

물론 'tr' 명령어를 사용하여 다음과 같이 구현해도 되긴 합니다.


cat test.out | tr "\n" ":" | cut -d ':' -f 1-5



하지만, 위 방법 역시도 '|'(pipe) 를 이용한 명령어의 길이가 길어지기도 하고 cut 명령 뒤에 '-f' 옵션으로 출력 컬럼을 정할 때에도 ':'(colon) 개수를 알아야만 한다는 단점이 있습니다.

posted by 박현명

이번 글은 sed 명령어를 이용하여 new line(개행문자 \n)을 특정 문자열로 바꾸거나, 특정 문자열을 new line으로 변경하는 방법에 대한 글입니다.

 

Shell Script를 작성하다 보면 한꺼번에 많은 내용을 바꾸어야 할 때가 종종 발생하는데, 그 때 유용하게 쓰이는 명령어가 바로 이 'sed' 명령어죠.

 

sed와 비슷한 역할을 하는 명령어로 'tr' 이라는 명령어도 있습니다.

 

각자가 처한 상황에 맞게, 취향에 따라 골라 쓰시면 되는데요.

 

그러한 내용 변경 상황 중에서도 new line, 다시 말해 줄바꿈 상태를 특정 문자열로 변경하거나, 그 반대로 특정 문자열을 줄바꿈 상태로 바꿔야 하는 경우가 있습니다.

 

그럴 때 다음과 같이 사용하시면 되겠습니다.

 

(1) 특정 문자열 --> new line


# cat test.txt

11111,22222,33333,44444,55555



위와 같은 문자열들로 이루어진 txt 파일이 있다고 가정합니다.

 

위 컨텐츠 중, ','(comma)를 new line으로 바꾸고자 한다면 다음과 같이 수행합니다.


# sed 's/,/\

> /g' test.txt > test1.txt



sed 명령에서 's' 옵션은 'switch' 를 뜻하는 옵션으로 뒤에 나오는 /A패턴/을 /B패턴/으로 바꾸겠다는 뜻입니다.

 

제일 뒤의 'g' 옵션은 'global' 을 뜻하는 옵션으로 /A패턴/이 여러 개일 경우 전부 바꾸겠다는 뜻이죠.

 

이 옵션을 주지 않으면 제일 첫 번째에 나타나는 /A패턴/ 한 개 문자열만 바뀌게 됩니다.

 

위 예시에서는 /A패턴/ 자리에 바뀌어야할 기존 문자열인 ','(comma) 를 입력하였습니다.

 

/B패턴/ 자리에 new line 을 뜻하는 문자열 입력을 위해 '\'(back slash)를 입력한 후 실제 Enter 버튼을 눌러 줄바꿈을 해줍니다.

 

UNIX나 LINUX 의 프롬프트 상에서 위 명령을 실행할 경우, 줄이 바뀌었다는 표시인 '>'(redirection) 기호가 나타납니다.

 

그러면 나머지 global 옵션이라든가, 파일 이름 등을 나열해 줍니다.

 

핵심은 '\'(back slash)와 Enter key 누름이 되는 것이구요.

 

Shell Script 상에서는 '>'(redirection) 표시가 되지 않을 것이기에 Enter 버튼을 누른 후 나머지 구문을 완성해 주시면 됩니다.

 

이 때 한 가지 주의하실 것은 Shell Script 작성을 보기 좋게 하고자 tab 키나 space 키로 들여쓰기를 하는 경우가 있는데, 위와 같이 특정 문자열을 new line으로 바꾸는 sed 문장을 작성하실 경우, Enter key 누름 효과 이후에 tab 키나 space 키를 적용하면 안됩니다.


sed 's/,/\

    > /g' test.txt > test1.txt   --> (X)

----

└> space 적용 부분

 

sed 's/,/\

> /g' test.txt > test1.txt       --> (O)



위와 같이 정상적으로 sed 명령이 수행되었다면 다음과 같은 결과가 나타나게 되겠죠.


# cat test1.txt

11111

22222

33333

44444

55555



이상 특정 문자열을 new line으로 변경하는 방법에 대해 말씀 드렸구요.

 

다음 글에서는 그 반대인 new line을 특정 문자열로 변경하는 방법에 대해서 말씀 드리도록 하겠습니다.

posted by 박현명
prev 1 2 next