쉘스크립트 기본 참고 사이트 : shell script 기본

1. for 문 활용

1) 특정 디렉토리내의 파일들의 내용을 보기

[root@RHEL63-1 ~]# for i in `ls /sys/class/iscsi_host/*/ipaddress`; do echo $i; cat $i; done
/sys/class/iscsi_host/host3/ipaddress
192.168.2.175
/sys/class/iscsi_host/host4/ipaddress
192.168.0.175
/sys/class/iscsi_host/host5/ipaddress
192.168.0.175
/sys/class/iscsi_host/host6/ipaddress
192.168.2.175

- iscsi host* 들에 대한 ipaddress 를 모두 보여주는 것이다.

- 아래와 같이 표현해도 된다.

#!/bin/bash
for i in `ls /sys/class/iscsi_host/*/ipaddress`; do
   echo $i
   cat $i
done

또는

[root@server ~]# cat /sys/class/scsi_host/host*/device/scsi_host/host*/state
running
running
running

[root@server ~]# find /sys/class/scsi_host/host*/device/scsi_host/host*/state -exec grep -H . {} \;
/sys/class/scsi_host/host0/device/scsi_host/host0/state:running
/sys/class/scsi_host/host1/device/scsi_host/host1/state:running
/sys/class/scsi_host/host2/device/scsi_host/host2/state:running

[root@server ~]# find /sys/class/scsi_host/host*/device/scsi_host/host*/state| xargs grep -H .
/sys/class/scsi_host/host0/device/scsi_host/host0/state:running
/sys/class/scsi_host/host1/device/scsi_host/host1/state:running
/sys/class/scsi_host/host2/device/scsi_host/host2/state:running

 

 

2) NIC 링크 상태 간략하게 뽑아보기

for LIST in `ifconfig -a | grep eth | awk '{print $1}'`; do echo "${LIST} - `ethtool ${LIST} | grep 'Link detected'`"; done
eth0 -  Link detected: yes
eth1 -  Link detected: yes
eth2 -  Link detected: yes
eth3 -  Link detected: no
eth4 -  Link detected: no
eth5 -  Link detected: yes

 

3) rm 문자를 포함하는 TEXT 파일 검출

시스템에 있는 모든 TEXT 파일의 내용을 뒤져서 rm 명령어가 포함되어 있는지를 확인, 포함하고 있는 파일은 화면에 출력한다.

#!/bin/bash

BEGIN_PATH=/

function check_rm()
{
    if [ -r $i ]; then
        for cmd in "/bin/rm\ " "/rm\ " "^rm\ " "\ rm\ ";
        do
            if grep -q "$cmd" $1; then
                echo $1;
            fi
        done
    fi
}

for d in $(ls $BEGIN_PATH);
do
    if [ $BEGIN_PATH == '/' ]; then
        local_path="/$d";
    else
        local_path="$BEGIN_PATH/$d";
    fi

    if [ -d $local_path ]; then
        for i in $(find $local_path -exec file {} \; | grep text | egrep -v "RPM|x86_64" | cut -d: -f1);
        do
            check_rm "$i"
        done
    elif [ -f $local_path ]; then
        for i in $(find $local_path -exec file {} \; | grep text | egrep -v "RPM|x86_64" | cut -d: -f1);
        do
            check_rm $local_path
        done
    fi
done

- rpm 파일은 rm 문자를 포함하는 검사에서 제외하고 진행한다.

 

4) 불필요한 LSB(Linux Standard Base) User에 대한 주석처리

프로젝트상 보안 스크립를 돌리면 아래 계정에 대한 보안 취약점이 존재한다고 할때가 있다.

이때 아래와 같은 스크립트를 적용하면 쉽게 해당 계정을 주석처리하여 workaround 할 수 있다.

#!/bin/bash
CREATE_FILE=`hostname`"_linux_"`date +%m%d`.txt

applyuser=`cat /etc/passwd | egrep "^ftp|^uucp|^lp|^sync|^halt|^shutdown|^games|^daemon|^bin|^sys|^adm|^newes|^gopher"|awk -F : '{print $1}'`  >> $CREATE_FILE 2>&1
for i in $applyuser
do
    #cat $CREATE_FILE |grep "1.01 결과 : 취약"
    #if [ $? == "0" ] ; then
        find /etc/passwd -exec perl -pi -e 's/^'$i'/#'$i'/g' {} \; > /dev/null 2>&1
        echo $i >> $CREATE_FILE 2>&1
    #fi
done

* 위 코드의 주석 부분을 해제 후 보안 스크립트 내에 삽입하면 보안 스크립트를 돌릴때 바로 적용할 수 있다.

또한 아래와 같은 코드로 수행을 시켜도 적용 가능하다.

#!/bin/bash
array_name=("ftp" "uucp" "lp" "sync" "halt" "shutdown" "games" "daemon" "bin" "sys" "adm" "news" "gopher")

for (( i = 0 ; i < ${#array_name[@]} ; i++ )) ; do
    #sed -i '/^'${array_name[$i]}'/s/'^${array_name[$i]}'/#'${array_name[$i]}'/g' /root/passwd
    sed -i 's/^'${array_name[$i]}'/#'${array_name[$i]}'/g' /root/passwd
    echo "${array_name[$i]}" user change to "#${array_name[$i]}"
done

 

5) 메모리 사용량 보기

아래 스크립트를 아래처럼 watch와 조합하여 실행하면 실시간 메모리 사용량 체크가 가능하다.

# watch -d -n1 memusage.sh

#!/bin/bash

echo "####################### USAGE REAL MEMOMRY PER USER #########################"
LIST_FILE=`ps -eo user,pid,rss,comm --sort -rss | awk '$3 > 0 {print $1}' | sort -u | grep -v "USER"`
TOTAL_SUM=0

for LIST in ${LIST_FILE};
do
    PROC_COUNT=`ps -eo user,pid,rss,comm --sort -rss | awk '$3 > 0 && $1 ~ /^'"${LIST}"'$/ {print $0}' | wc -l`
    MEM_LIST=`ps -eo user,pid,rss,comm --sort -rss | awk '$3 > 0 && $1 ~ /^'"${LIST}"'$/ {print $3}'`
    MEMSUM=0

    for M_LIST in ${MEM_LIST};
    do
        MEMSUM=`expr ${MEMSUM} + ${M_LIST}`
    done

    TOTAL_SUM=`expr ${TOTAL_SUM} + ${MEMSUM}`

    echo -e "[USER=${LIST}]\t\t[Process=${PROC_COUNT}]\t\t[Real Mem=${MEMSUM} KByte]"
done
echo
TOTAL=$(echo "(" ${TOTAL_SUM}") / 1024" | bc)
echo "Total Use Real Memory = $TOTAL MB"
echo "#############################################################################"
echo

echo "############################## DISK CACHE USAGE #############################"
BUF=$(echo "(" $(cat /proc/meminfo | grep -e Buffers -e '^Cached' | awk '{print $2}' | paste -s -d "+") ") /1024" | bc)
| paste -s -d "+" | bc)
ACT=$(echo "(" $(cat /proc/meminfo | grep -e 'Active(file)' -e 'Inactive(file)' -e Shmem | awk '{print $2}' | paste -s -d "+") ") / 1024" | bc)
echo "Buffers + Cached = "$BUF" MB"
echo "Active(file) + Inactive(file) + Shmem = "$ACT" MB"
echo "#############################################################################"

 

6) 파일의 내용을 라인별로 읽어서 2개의 컬럼 데이터를 동시에 출력

# cat list.txt 
192.168.1.82 645d161c-33c1-7e7b-0657-832cb3ff2a91
192.168.1.83 645d161c-33c1-7e7b-0657-832cb3ff2a92
192.168.1.84 645d161c-33c1-7e7b-0657-832cb3ff2a93

스크립트 방법 1)
중첩 for문 활용

#!/bin/bash
SSH_OPTION="-o ConnectTimeout=3 -o StrictHostKeyChecking=no"
NODE=$(awk -F'\t' '{print $1}' list.txt)
UUID=$(awk -F'\t' '{print $2}' list.txt)

c=0
for i in $NODE
do
    for j in $i
    do
        ARR=($UUID)
        echo $j
        echo ${ARR[c]};
        #sshpass -p "##" ssh -q $SSH_OPTION root@$j "xe vm-shutdown --force uuid=${ARR[c]}" &
        c=$((c+1))
    done
done

--> 두번째 for문에서 ARR array에 두번째 컬럼 값을 넣고 array 0번부터 출력. 여기서는 3줄만 있으므로 0 ~ 2 까지 두번째 for loop가 돌면서 

방법 2)
while read 문 활용

#!/bin/bash

SSH_OPTION="-o ConnectTimeout=3 -o StrictHostKeyChecking=no"
while read line
do
    NODE=$(echo $line | awk -F' ' '{print $1}')
    UUID=$(echo $line | awk -F' ' '{print $2}')

echo "$NODE"
echo "$UUID"
#sshpass -p "##" ssh -q $SSH_OPTION root@$NODE "xe vm-shutdown --force uuid=$UUID" &

done < list.txt

결과 (결과는 방법 1, 2 모두 동일)

# ./test.sh 
192.168.1.82
645d161c-33c1-7e7b-0657-832cb3ff2a91
192.168.1.83
645d161c-33c1-7e7b-0657-832cb3ff2a92
192.168.1.84
645d161c-33c1-7e7b-0657-832cb3ff2a93

만약 for 문에서 단순 중첩 for문을 이용하면 아래처럼 출력이 된다.

# ./test.sh 
192.168.1.82
645d161c-33c1-7e7b-0657-832cb3ff2a91
645d161c-33c1-7e7b-0657-832cb3ff2a92
645d161c-33c1-7e7b-0657-832cb3ff2a93
192.168.1.83
645d161c-33c1-7e7b-0657-832cb3ff2a91
645d161c-33c1-7e7b-0657-832cb3ff2a92
645d161c-33c1-7e7b-0657-832cb3ff2a93
192.168.1.84
645d161c-33c1-7e7b-0657-832cb3ff2a91
645d161c-33c1-7e7b-0657-832cb3ff2a92
645d161c-33c1-7e7b-0657-832cb3ff2a93 

즉, 아래처럼 단순히 두번째 for문을 작성하면 두번째 컬럼이 위와 같이 한번에 모두 출력이 됨.

for i in $NODE
do
    echo $i
    for j in $UUID
    do
        echo $j
    done
done

또는

for i in $NODE
do
    echo $i
    ARR=($UUID)
    for (( j=0; j<${#ARR[@]}; j++ ));
    do
        echo ${ARR[j]} 
    done
done

[ 참조 ]

2. while 문 활용

1) 특정 디렉토리 내의 파일 및 디렉토리 리스트 보기

[root@RHEL63-1 ~]# while :;do ls -la /tmp; sleep 1; clear; done;
total 1230484
drwxrwxrwt.  4 root  root      4096 Aug 26 03:32 .
dr-xr-xr-x. 29 root  root      4096 Aug 22 13:46 ..
-rwx------.  1 root  root      2361 Aug 16 15:35 dropcacherun.sh_2016081601
drwxrwxrwt   2 root  root      4096 Aug 18 13:22 .ICE-unix
-rw-r--r--.  1 root  root      3481 Aug 17 10:30 mcetrace.log
srwxrwxrwx   1 dbadm dba          0 Aug 24 10:55 mysql.sock
drwxr-xr-x.  2 root  root      4096 Aug 17 18:28 suds
-rw-------   1 root  root    155849 Aug 18 19:09 tmpDpnySm
-rw-------   1 root  root    155849 Aug 18 19:09 tmpSwf3ya
-rw-------   1 root  root    155849 Aug 18 19:10 tmpTEzfkR
-rw-------   1 root  root    155849 Aug 18 19:09 tmpz17srj

- /tmp 디렉토리를 1초 단위로 reflesh 하면서 출력해 준다.

- 아래와 같이 표현해도 된다.

#!/bin/bash
while :; do
    ls -la /tmp
    sleep 1
    clear
done

또는 watch를 이용해서 간단하게 실행할 수도 있다.

[root@RHEL63-1 ~]# watch -d -n1 'ls -la /tmp'

 

2) 10초간만 /tmp 디렉토리의 파일/디렉토리를 리스트업 하고 끝낸다.

#!/bin/bash
num=10
while [ $num -ge 1 ]; do
    ls -la /tmp
    sleep 1
    clear
    num=$((num-1))
done

 

3) 어떠한(여기서는 crsctl) 상태를 3초에 한번씩 date를 찍으며 계속 모니터링 하기.

# while true
do
    echo "###########"
    date
    crsctl stat res -t
    sleep 3
done

- 아래와 같이 한줄로 표현할 수도 있다.

# while true :; do echo "###########" ; date; crsctl stat res -t; sleep 3; done

 

4) TCPBacklogDrop 값을 확인

# cat /proc/net/netstat | awk '(f==0) {name=$1; i=2; while ( i<=NF) {n[i] = $i; i++ }; f=1; next} (f==1){ i=2; while ( i<=NF){ printf "%s%s = %d\n", name, n[i], $i; i++}; f=0} ' | grep TCPBacklogDrop

* 만약 전체 내용을 확인 하고자 하면 맨 뒤의 grep TCPBacklogDrop을 제거한다.

 

5) 모든 프로세스의 RSS 값(메모리 사용량) 합산해서 보기

# while :; do clear; echo "(" $(ps -eo rss | egrep -v ' 0' | egrep -v RSS | paste -s -d "+") ") / 1024" | bc ; sleep 1 ; done

 

6) tmpfs (/dev/shm) 메모리 파일시스템에 랜덤한 파일 생성하기

# while :; do RNUM=$(shuf -i 1-10000 -n 1); dd if=/dev/zero of=/dev/shm/file.`echo $RNUM` count=1 bs=10M status=progress ; echo "created file: /dev/shm/file.$RNUM" ; sleep 1 ; clear ; done
1+0 records in
1+0 records out
10485760 bytes (10 MB) copied, 0.00659528 s, 1.6 GB/s
created file: /dev/shm/file.8329

* /dev/shm에 file.XXXX 이름의 10MB 용량의 파일이 1초 단위로 용량이 full이 될 때까지 생성된다.

* dd 버전이 낮으면 'status=progress' 옵션이 없을 수 있다. 그럴 경우 이 옵션은 제외하고 실행.

수행 후 아래와 같이 메모리 캐시 및 스왑 정리

# sync
# echo 3 > /proc/sys/vm/drop_caches
# echo 0 > /proc/sys/vm/drop_caches
# swapoff -a
# swapon -a

* 수행 전 프로세스 메모리 상태를 보고 수행할 것.

- 만약 /dev/shm의 RHEL 기본 사이즈인 메모리의 50%에서 95%로 조정하고 싶다면 아래와 같이 수행

# mount -o defaults,size=$(free -m | grep Mem | awk '{printf "%.0f",$2 * 95 / 100}')m,remount /dev/shm

 

  • dialog와 dd 연동

(pv -n /dev/sda | dd of=/dev/sdb bs=128M conv=notrunc,noerror) 2&gt;&amp;1 | dialog --gauge "Running dd command (cloning), please wait…" 10 70 0

 

3. AWK, grep, sed, cut 활용

1) AWK를 활용하여 디스크들의 총합을 구하는 것이다.

[root@RHEL63-1 ~]# cat /proc/partitions | grep sd* | egrep -v [1-9]$
major minor  #blocks  name
   8        0   33554432 sda
   8       16   52428800 sdb
   8       32   52428800 sdc
   8       48   52428800 sdd
   8       64   52428800 sde
   8       80   26214400 sdf
   8       96   26214400 sdg
   8      112   26214400 sdh
   8      128   26214400 sdi

[root@RHEL63-1 ~]# cat /proc/partitions | grep sd* | egrep -v [1-9]$ | awk '{ SUM+=$3 } END { print SUM/1024/1024 " GB" }'
332 GB

- SUM+=$3 마치 while 문처럼 동작을 한다. $3 필드값을 모두 더한다.

- 총합이 332GB 이다.

 

2) grep 활용

- 파티션 정보 중 공백을 기준으로 네번째 필드만 출력

[root@RHEL63-1 ~]# cat /proc/partitions | awk '{ print $4 }'
name

loop0
sda
sda1
sda2
dm-0
dm-1
sdb
sdc
dm-2
dm-3
sdd
sde
dm-5
dm-4
sdf
sdg
dm-6
dm-7
sdh
sdi
dm-8

- 네번째 필드에서 맨앞 문자가 d 또는 s로 시작하는 값들만 출력

[root@RHEL63-1 ~]# cat /proc/partitions | awk '{ print $4 }' | grep ^[ds]
sda
sda1
sda2
dm-0
dm-1
sdb
sdc
dm-2
dm-3
sdd
sde
dm-5
dm-4
sdf
sdg
dm-6
dm-7
sdh
sdi
dm-8

 

- grep과 정규표현식을 이용하여 8자리 단위로 쪼개서 배열에 넣고 출력하기. 

# array_name[1]=$(echo b5f1e7bfc2439c621353d1ce0629fb8b | grep -o '[a-f0-9]\{8\}')
# echo ${array_name[1]}
b5f1e7bf c2439c62 1353d1ce 0629fb8b
# echo ${array_name[@]}
b5f1e7bf c2439c62 1353d1ce 0629fb8b

# array_name[2]=$(echo b5f1e7bfc2439c621353d1ce0629fb8b | grep -o '[a-f0-9]\{8\}')
# echo ${array_name[2]}
b5f1e7bf c2439c62 1353d1ce 0629fb8b
# echo ${array_name[@]}
b5f1e7bf c2439c62 1353d1ce 0629fb8b b5f1e7bf c2439c62 1353d1ce 0629fb8b

# array_name[3]=$(echo b5f1e7bfc2439c621353d1ce0629fb8b | grep -o '[a-f0-9]\{8\}')
# echo ${array_name[3]}
b5f1e7bf c2439c62 1353d1ce 0629fb8b
# echo ${array_name[@]}    --> #print array_name all item
b5f1e7bf c2439c62 1353d1ce 0629fb8b b5f1e7bf c2439c62 1353d1ce 0629fb8b b5f1e7bf c2439c62 1353d1ce 0629fb8b

# echo ${array_name[*]}    --> #print array_name all item
b5f1e7bf c2439c62 1353d1ce 0629fb8b b5f1e7bf c2439c62 1353d1ce 0629fb8b b5f1e7bf c2439c62 1353d1ce 0629fb8b

# echo ${!array_name[@]}   --> #print array_name index number
1 2 3

# echo ${#array_name[@]}   --> #print array_name size
3

또는

# array_name=( $(echo b5f1e7bfc2439c621353d1ce0629fb8b | grep -o '[a-f0-9]\{8\}') )

# echo ${array_name[@]}
b5f1e7bf c2439c62 1353d1ce 0629fb8b

 

3) messages 로그 파일 특정 시간 단위만 출력 하기

- messages 로그들 중 2월 22일, 24일 날짜의 15시 00분 00초 ~ 18시 20분 00초 사이의 로그만 출력

# cat /var/log/messages* | awk '$3 >= "15:00:00" && $3 <= "18:20:00"' | grep -e "Feb 22" -e "Feb 24"

- messages 로그들 중 2월 2일 날짜만 제외하고 15시 00분 00초 ~ 18시 20분 00초 사이의 로그만 출력

# cat /var/log/messages* | awk '$3 >= "15:00:00" && $3 <= "18:20:00"' | grep -v "Feb  2"

 

4) 리눅스 유저 계정 생성일 확인하기

- gnome 이 설치되어 있는데 RunLevel 3로 운영한 시스템의 사용자 계정 생성일을 찾는 스크립트 임.

# find $(awk -F: '{if ($3 >= 999) { print $(NF-1) } }' /etc/passwd | grep -v 'lib/nfs') -maxdepth 3 -type d -name '.mozilla' | xargs ls -Alct --full-time | grep plugins | awk -F " " '{ print $3 " " $4 " " $6 }'

서버에 따라 이 방법으로 찾을 수 없을 수도 있다. 참고만 할 것.
계정 생성 후 도중에 계정 비번을 변경하는 등.. 세월이 많이 흐른 뒤 서버의 계정들의 최초 생성일을 정확히 알 방법이 딱히 없다. 혹시 아는분은 답글로 남겨주시길..

 

5) grub.conf의 UUID 수정

ASIS : RHEL 6.2 on HP DL380 G8 (G8 기종 EOS)
TOBE : RHEL 6.8 on HP DL380 G9
HP가 Certification을 하지 않기 때문에 G8의 6.2 OS HDD를 DL380 G9으로 옮긴 후 Upgrade를 하지 못하는 상황. 따라서 G9에 RHEL 6.8을 신규 설치 후 마이그레이션 진행함.
RHEL 6.2 -> RHEL 6.8 으로 마이그레이션 과정 중 기존 환경파일 grub.conf를 그대로 복사 후 root=UUID를 sed 변경하는.. RHEL 6.8에서 아래와 같이 수행한다.
LVM을 사용하지 않았을 경우에만 해당된다. 그리고 root 파티션 /dev/sda1 는 환경에 맞게 변경.

아래 3가지 방법 모두 동일한 결과가 반영됨.
[root@RHEL68 ~]# sed -i 's/root=UUID=[a-zA-Z|0-9|\-]*/root\=UUID='$(tune2fs -l /dev/sda1 | grep UUID | awk '{print $3}')'/g' /boot/grub/grub.conf
[root@RHEL68 ~]# sed -i 's/root=UUID=?*[a-zA-Z|0-9|\-]*/root\=UUID='$(tune2fs -l /dev/sda1 | grep UUID | awk '{print $3}')'/g' /boot/grub/grub.conf
[root@RHEL68 ~]# sed -i 's/root=UUID=?*...................................../root\=UUID='$(tune2fs -l /dev/sda1 | grep UUID | awk '{print $3}')'\ /g' /boot/grub/grub.conf

 

6) sed 대소문자 치환

원래 파일 내용
[root@localhost ~]# cat aa.txt 
123abC
EOerJL

대문자를 모두 소문자(Lower Case)로 변경
[root@localhost ~]# sed 's/.*/\L&/' aa.txt 
123abc
eoerjl

소문자를 모두 대문자(Upper Case)로 변경
[root@localhost ~]# sed 's/.*/\U&/' aa.txt 
123ABC
EOERJL

 

7) fuser 결과값 파일로 저장

명령행에서는 아래처럼 출력이 되지만
[root@localhost ~]# /sbin/fuser -cu /tmp
/tmp:                    1rce(root)     2rc(root)     3rc(root)     4rc(root)     5rc(root)     6rc(root)     7rc(root)     8rc(root)     9rc(root)    10rc(root)    11rc(root)    12rc(root)    13rc(root)    14rc(root)    15rc(root)    16rc(root)    17rc(root)    18rc(root)    19rc(root)    20rc(root)    21rc(root)    22rc(root)    23rc(root)    24rc(root)    25rc(root)    26rc(root)    27rc(root)    28rc(root)    29rc(root)    30rc(root)    31rc(root)    32rc(root)    33rc(root)    34rc(root)    35rc(root)    36rc(root)    37rc(root)    38rc(root)    39rc(root)    40rc(root)    41rc(root)    42rc(root)    43rc(root)    45rc(root)    46rc(root)    47rc(root)    48rc(root)    49rc(root)    50rc(root)    51rc(root)    52rc(root)    59rc(root)    60rc(root)    61rc(root)    63rc(root)    64rc(root)    65rc(root)    97rc(root)    98rc(root)   289rc(root)   290rc(root)   302rc(root)   303rc(root)   438rc(root)   439rc(root)   537rce(root)   773rc(root)  1193rc(root)  1194rc(root)  1195rc(root)  1196rc(root)  1232rc(root)  1417rce(root)  1477rce(root)  1499rce(rpc)  1512rce(dbus)  1633rce(root)  1661rce(root)  1673rce(root)  1789rce(root)  1796rce(root)  1798rce(root)  1800rce(root)  1802rce(root)  1804rce(root)  1806rce(root)  1811rce(root)  1812rce(root)  1855rce(root)  1856rce(root)  1866rce(root)  1869rc(root)  1928rce(root)  2368rce(root)  5420rce(root)  5422rc(root)  5423rce(root) 11499rce(root) 29271rce(apache) 29272rce(apache) 29273rce(apache) 29274rce(apache) 29275rce(apache) 29277rce(apache) 29278rce(apache) 29279rce(apache)

화면 출력을 파일로 redirect 하면 제대로 출력이 되지 않는다.
[root@localhost ~]# /sbin/fuser -fcu /tmp > /root/resultfuser.txt
/tmp:               rce(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rce(root)rc(root)rc(root)rc(root)rc(root)rc(root)rc(root)rce(root)rce(root)rce(rpc)rce(dbus)rce(root)rce(root)rce(root)rce(root)rce(root)rce(root)rce(root)rce(root)rce(root)rce(root)rce(root)rce(root)rce(root)rce(root)rce(root)rc(root)rce(root)rce(root)rce(root)rce(root)rce(root)rce(apache)rce(apache)rce(apache)rce(apache)rce(apache)rce(apache)rce(apache)rce(apache)
[root@localhost ~]# cat /root/resultfuser.txt
     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    32    33    34    35    36    37    38    39    40    41    42    43    45    46    47    48    49    50    51    52    59    60    61    63    64    65    97    98   289   290   302   303   438   439   537   773  1193  1194  1195  1196  1232  1417  1477  1499  1512  1633  1661  1673  1789  1796  1798  1800  1802  1804  1806  1811  1812  1855  1856  1866  1869  1928  2368  5420  5423 11499 29271 29272 29273 29274 29275 29277 29278 29279

아래와 같이 표준에러를 표준출력(2>&1)으로 redirection 하면 원하는 결과값을 파일로 저장할 수 있다.
[root@localhost ~]# /sbin/fuser -fcu /tmp > /root/resultfuser.txt 2>&1
[root@localhost ~]# cat /root/resultfuser.txt
/tmp:                    1rce(root)     2rc(root)     3rc(root)     4rc(root)     5rc(root)     6rc(root)     7rc(root)     8rc(root)     9rc(root)    10rc(root)    11rc(root)    12rc(root)    13rc(root)    14rc(root)    15rc(root)    16rc(root)    17rc(root)    18rc(root)    19rc(root)    20rc(root)    21rc(root)    22rc(root)    23rc(root)    24rc(root)    25rc(root)    26rc(root)    27rc(root)    28rc(root)    29rc(root)    30rc(root)    31rc(root)    32rc(root)    33rc(root)    34rc(root)    35rc(root)    36rc(root)    37rc(root)    38rc(root)    39rc(root)    40rc(root)    41rc(root)    42rc(root)    43rc(root)    45rc(root)    46rc(root)    47rc(root)    48rc(root)    49rc(root)    50rc(root)    51rc(root)    52rc(root)    59rc(root)    60rc(root)    61rc(root)    63rc(root)    64rc(root)    65rc(root)    97rc(root)    98rc(root)   289rc(root)   290rc(root)   302rc(root)   303rc(root)   438rc(root)   439rc(root)   537rce(root)   773rc(root)  1193rc(root)  1194rc(root)  1195rc(root)  1196rc(root)  1232rc(root)  1417rce(root)  1477rce(root)  1499rce(rpc)  1512rce(dbus)  1633rce(root)  1661rce(root)  1673rce(root)  1789rce(root)  1796rce(root)  1798rce(root)  1800rce(root)  1802rce(root)  1804rce(root)  1806rce(root)  1811rce(root)  1812rce(root)  1855rce(root)  1856rce(root)  1866rce(root)  1869rc(root)  1928rce(root)  2368rce(root)  5420rce(root)  5423rce(root)  5481rc(root) 11499rce(root) 29271rce(apache) 29272rce(apache) 29273rce(apache) 29274rce(apache) 29275rce(apache) 29277rce(apache) 29278rce(apache) 29279rce(apache)

 

8) netstat 로컬 ip address 의 특정 포트 영역 사용 중 확인

[root@testserver ~]# netstat -na | awk -F'[[:space:]]+|:' 'NR>2 && $5>=12000 && $5<=12900'

12000 ~ 12900 범위의 현재 사용중인 포트 출력

 

9) 특정 라인 주석 제거 및 삽입

  • 주석 제거
# sed -ri 's/^#(.*sufficient\s+pam_wheel\.so trust use_uid.*)/\1/' /etc/pam.d/su

#auth       sufficient  pam_wheel.so trust use_uid
(위 라인의 주석이 제거됨)

-> sed의 -r 옵션을 통해 regular expression을 활성화하여 좀 더 디테일하게 문자를 다룬다.

 

  • 주석 삽입
# sed -ri 's/(.*sufficient\s+pam_wheel\.so trust use_uid.*)/#\1/' /etc/pam.d/su

 

  • 주석 삽입(이중 주석 방지)

하지만 주석이 이미 있는 경우 위와 같이 주석을 삽입하게 되면 주석이 또 삽입된다.

아래와 같이 주석이 없는 라인만을 대상으로 해당 필터된 라인에 대해 주석을 넣는 방식을 사용하면 이중 주석의 문제가 해결된다.

# sed -ri '/(^#)/! s/(.*sufficient\s+pam_wheel\.so trust use_uid.*)/#\1/' /etc/pam.d/su

-> 라인의 첫번째 문자가 #으로 시작하지 않는 라인에 대해서만 해당 필터 문구에 대해서 주석을 넣겠다는 의미.

 

  • 각 기호에 대한 설명
s/                            # Substitute  
^#                            # A line starting with a #
(                             # Start capture group
.*                            # Followed by anything
sufficient                    # Followed by the word sufficient
\s+                           # Followed by whitespace
pam_wheel\.so trust use_uid   # Followed by the literal string (escaped .)
.*                            # Followed by anything
)                             # Stop capture group
/                             # Replace with 
\1                            # The first capture group 

 

10) for 문을 이용한 여러개의 도메인에 순차적으로 한번에  icmp 패킷 전송 (ping)

# for i in nodea.{cluster1,private,storage{1,2}}.example.com; do
> ping -c 1 ${i}
> done

위와 같이 수행시 아래 도메인으로 ping

nodea.cluster1.example.com
nodea.private.example.com
nodea.storage1.example.com
nodea.storage2.example.com

 

11) APNIC ip 대역 리스트에서 국가별 총 IP 갯수를 도출하기

2번째(국가), 5번째(ip 갯수)를 출력하고 국가별로 총합을 구한 리스트를 만들기

아래 URL에서 원본 파일을 다운받을 수 있다

https://ftp.apnic.net/stats/apnic/delegated-apnic-extended-latest

[root@pyhost ~]# cat delegated-*
2.3|apnic|20200912|134221||20200911|+1000
apnic|*|asn|*|10837|summary
apnic|*|ipv4|*|46677|summary
apnic|*|ipv6|*|76707|summary
apnic|AU|ipv4|1.0.0.0|256|20110811|assigned|A91872ED
apnic|CN|ipv4|1.0.1.0|256|20110414|allocated|A92E1062
apnic|CN|ipv4|1.0.2.0|512|20110414|allocated|A92E1062
apnic|AU|ipv4|1.0.4.0|1024|20110412|allocated|A9192210
apnic|CN|ipv4|1.0.8.0|2048|20110412|allocated|A92319D5
apnic|JP|ipv4|1.0.16.0|4096|20110412|allocated|A92D9378
apnic|CN|ipv4|1.0.32.0|8192|20110412|allocated|A92319D5
apnic|JP|ipv4|1.0.64.0|16384|20110412|allocated|A9252414
apnic|TH|ipv4|1.0.128.0|32768|20110408|allocated|A91CF4FE
apnic|CN|ipv4|1.1.0.0|256|20110414|allocated|A92E1062
apnic|AU|ipv4|1.1.1.0|256|20110811|assigned|A91872ED
apnic|CN|ipv4|1.1.2.0|512|20110414|allocated|A92E1062
apnic|CN|ipv4|1.1.4.0|1024|20110414|allocated|A92E1062
apnic|CN|ipv4|1.1.8.0|256|20110412|allocated|A91E9A58
apnic|CN|ipv4|1.1.9.0|256|20110412|allocated|A92319D5
apnic|CN|ipv4|1.1.10.0|512|20110412|allocated|A92319D5
apnic|CN|ipv4|1.1.12.0|1024|20110412|allocated|A92319D5
apnic|CN|ipv4|1.1.16.0|4096|20110412|allocated|A92319D5
apnic|CN|ipv4|1.1.32.0|8192|20110412|allocated|A92319D5
apnic|JP|ipv4|1.1.64.0|16384|20110412|allocated|A92D9378
apnic|TH|ipv4|1.1.128.0|32768|20110408|allocated|A91CF4FE
apnic|CN|ipv4|1.2.0.0|512|20110414|allocated|A92E1062
apnic|CN|ipv4|1.2.2.0|256|20110331|assigned|A9272682
~~ snip ~~

[root@pyhost ~]# cat delegated-* | grep -v summary | awk -F"|" '$3=="ipv4" && $2!="" {print $2, $5}' | sort | awk '{x[$1]+=$2} END { for (i in x) print i "\t" x[i] }' | sort -nrk2
CN	340707584
JP	190012928
KR	112455424
AU	54872064
IN	41104640
TW	35703552
SG	22695936
~~ snip ~~



특정 변수가 숫자인지 아닌지 판별하기


MYVAL=2A

RE='^[0-9]+$'
if ! [[ $MYVAL =~ $RE ]] ; then
echo "$MYVAL is not a number" >&2;
else
echo "$MYVAL is a number"
fi

 


특정 파일의 라인별 값을 따옴표로 묶고 쉼표로 구분해서 일렬로 출력하기


[root@ex342 ~]# cat aa.txt
24796
7827
23982
2309
54984
[root@ex342 ~]# echo `awk '{ print "\""$0"\"" }' aa.txt` | sed "s/ /, /g;s/\"/\'/g"
'24796', '7827', '23982', '2309', '54984'
[root@ex342 ~]# echo `awk '{ print "'\''"$0"'\''" }' aa.txt` | sed "s/ /, /g"
'24796', '7827', '23982', '2309', '54984'
[root@ex342 ~]# echo `awk '{ print "\047"$0"\047" }' aa.txt` | sed 's/ /, /g'
'24796', '7827', '23982', '2309', '54984'

crontab의 특정 패턴(단어)이 포함된 라인만 삭제
[root@cent77 test]# crontab -l
* * * * * echo "hello world"
* * * * * echo "hi world"
* * * * * echo "yes world"

[root@cent77 test]# crontab -l | grep -v "hello" | crontab -

[root@cent77 test]# crontab -l
* * * * * echo "hi world"

crontab의 특정 패턴(단어)이 포함된 라인만 제외하고 모두 삭제
[root@cent77 test]# crontab -l
* * * * * echo "hello world"
* * * * * echo "hi world"
* * * * * echo "yes world"

[root@cent77 test]# crontab -l | grep "hello" | crontab -

[root@cent77 test]# crontab -l
* * * * * echo "hello world"


grep 활용

[student@workstation ~]$ oc status

In project iuygaw-application on server https://api.na46.prod.nextcle.com:6443


svc/mysql - 172.30.114.192:3306

pod/mysql runs registry.redhat.io/rhel8/mysql-80:1


http://todoapi-iuygaw-application.apps.na46.prod.nextcle.com to pod port 30080 (svc/todoapi)

pod/todoapi runs quay.io/redhattraining/do180-todonodejs-12


View details with 'oc describe <resource>/<name>' or list resources with 'oc get all'.


 


[student@workstation ~]$ oc status | grep -o "http:.*com"

http://todoapi-iuygaw-application.apps.na46.prod.nextcle.com


 # grep ^root: /etc/passwd /etc/shadow /etc/group | awk -F: 'BEGIN{OFS=":"}/shadow/{gsub(/.*/,"XXXXX",$3)}1'

/etc/passwd:root:x:0:0:root:/root:/bin/bash

/etc/shadow:root:XXXXX:18927:0:99999:7:::

/etc/group:root:x:0:

curl로 특정 파일 여러개 다운로드

- 아래와 같이 웹사이트의 특정 디렉토리 내에 여러가지 형태의 파일들이 포함되어있다.
# curl -s --list-only https://cdn.kernel.org/pub/linux/kernel/v5.x/
...
<a href="linux-5.9.9.tar.gz">linux-5.9.9.tar.gz</a>                             18-Nov-2020 18:30    173M
<a href="patch-5.9.9.xz">patch-5.9.9.xz</a>                                     18-Nov-2020 18:30    491K
<a href="ChangeLog-5.9.9">ChangeLog-5.9.9</a>                                   18-Nov-2020 18:30    329K
-> 이 중에서 ChangeLog 파일만 별도로 다운 받고 싶다면 아래와 같이 진행

- 특정 파일들(ChangeLog 파일만 다운로드)
# for i in $(curl -s --list-only https://cdn.kernel.org/pub/linux/kernel/v5.x/ | grep ChangeLog | awk '{print $2}' | awk -F '"' '{print $2}')
    do curl -O https://cdn.kernel.org/pub/linux/kernel/v5.x/$i
done

- 받은 ChangeLog 텍스트 파일의 내용에서 특정 패턴의 구문을 검색
# find . -type f | xargs grep 'xfs_btree_insert+0x1ec'

마지막 필드만 제외하고 출력 (awk)

- 마지막 필드만 제외하고 출력
# echo '/data/nice/abc/asda' | awk -F '/' 'sub(FS $NF,x)'
/data/nice/abc

- Path에서 최종 디렉토리만 출력
# basename /var/spool/cron
cron
shell script tip
태그:                                                         

shell script tip”에 대한 2개의 생각

  • 2018년 7월 13일 2:34 오후
    고유주소

    정규표현식 사용 by 상우

    응답
    • 2018년 9월 6일 1:41 오후
      고유주소

      상우 과장 잘 지내죠? ^^

      응답

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다