Profile picture

[Shell-Script] 그 동안 사용했던 셸 스크립트 모음

JaehyoJJAng2023년 03월 12일

파일 & 문자열 비교문

파일 비교문

-d file  : 파일이 존재하고 디렉토리인지 검사
-e file  : 파일이 존재하는지 검사
-f file  : 파일이 존재하고 파일인지 검사
-r file  : 파일이 존재하고 읽을 수 있는지 검사
-s file  : 파일이 존재하고 비어 있지 않은지 검사
-x file : 파일이 존재하고 실행할 수 있는지 검사

문자열 비교문

-n str : str의 길이가 0보다 큰지 검사
-z str : str의 길이가 0인지 검사

한 줄 스크립트 #1

파일 용량 확인하기

ls -alh /var/log | sort -k 5 -r | awk '{print $9 "  -  " $5}'

한 줄 스크립트 #2

타 서버의 루트 파티션 용량 체크하기

ssh nfs-client@192.168.219.124 -p 9706 "df -h | grep \"/dev/sda*\""

한 줄 스크립트 #3

ssh 명령 전송

ssh nfs-client@192.168.219.124 -p 9706 "ls -alh /var/log && df -h

한 줄 스크립트 #4

현재 경로에 tmp 디렉토리가 없는 경우 생성 후 , 파일 생성 & 파일 읽기

if [[ ! -d ./tmp ]]; then mkdir ./tmp; fi && touch ./tmp/tmp.txt; echo "tmp" > ./tmp/tmp.txt; cat./tmp/tmp.txt

한 줄 스크립트 #5

서버에서 sshd 프로세스 갯수 확인

$ ssh nfs-client@x.x.x.x -p 9706 'ps -ef | grep sshd* | grep -v grep | wc | awk '{print $1}''

한 줄 스크립트 #6

파일 찾기

if [[ -e /var/log/syslog ]]; then cat /var/log/syslog | tail -n 15; else echo "파일 없음";fi

숫자 맞추기

GOAL=$[ ${RANDOM}% 100+1  ] # OR GOAL=$((${RANDOM}% 100+1))

loop=true
COUNT=1
while [ "${loop}" ];
do
    # 입력 기회 20번으로 제한
    if [[ ${COUNT} -eq 21 ]]; then
        echo "아쉽네요, 다음 기회에 !"
        break
    fi

    read -p "1~100 까지의 숫자를 입력해보세요 (게임 종료 : 'q') : " num

    # 사용자가 'q'를 누른 경우
    if [[ ${num} = "q" ]]; then
        echo "게임이 종료됩니다"
        echo""
        break
    fi

    # 입력된 값이 없는경우
    if [[ ! ${num} ]]; then
           echo "숫자가 입력되지 않았습니다! 다시 입력해주세요"
           echo ""
    fi

    # 지정된 범위를 초과하는 경우
    if [[ ${num} -gt 100 ]]; then
        echo "숫자가 너무 커요! 다시 입력해주세요 (1 ~ 100)"
        echo ""
        continue
    elif [[ ${num} -lt 0 ]]; then
        echo "숫자가 지정된 범위보다 작습니다 (1 ~ 100)"
        echo ""
        continue
    fi

    # 숫자가 아닌 값이 입력 되었을 경우
    if [[ ${num} =~ [^0-9]$ ]]; then
        echo -e "입력된 값이 숫자가 아닙니다!\n입력하신 값 : ${num}"
        continue
    fi

    # 숫자 비교
    if [[ ${num} -gt ${GOAL} ]]; then
        echo -e "입력 값이 더 커요 ! \n남은 기회 : $((20 - ${COUNT}))"
    elif [[ ${num} -lt ${GOAL} ]]; then
        echo -e "입력 값이 더 작아요 ! \n남은 기회 : $((20 - ${COUNT}))"
    elif [[ ${num} -eq ${GOAL} ]]; then
        echo "축하합니다! 총 ${COUNT}번 만에 맞추셨어요!"
        break # exit 0 : while / shell 스크립트 종료 코드 ( 성공 )
              # exit 1 : ( 실패 )
              # echo ${?}
    fi

    ((COUNT+=1)) # ((COUNT=COUNT + 1 )) , $((COUNT+=1)) , $[ COUNT+=1 ]
done

디스크 용량 체크

#!/bin/bash

PER=${1}

if [[ ${#} -ne 1 ]]; then
    echo -e "해당 스크립트 사용방법\n${0} [PERCENT ( 1 ~ 100 % )]"
    exit 1
fi

if [[ ${PER} -gt 100 ]] || [[ ${PER} -lt 0 ]]; then
    echo -e "PERCENT : 1 ~ 100\n다시 입력해주세요"
    exit 1
fi

if [[ ${PER} =~ [^0-9] ]]; then
    echo -e "DISK PERCENT를 입력해주세요 [ 1 ~ 100 ]"
    exit 1
fi

DISK_LISTS=($(df -h | awk '{gsub(/%/,""); print $5}' | grep -vi 'use'))
MNT=($(df -h | awk '{gsub(/%/,""); print $6}' | grep -vi "mounted" ))

for idx in "${!DISK_LISTS[@]}";
do
    disk="${DISK_LISTS[${idx}]}"
    mount="${MNT[${idx}]}"
    if [[ $disk -ge ${PER} ]]; then
        echo -e "${disk}\t${mount}\n"

    fi
done

확장자 파일 이동

#!/bin/bash

function AUTOMATION_DIR() {                     
    PATH_AFTER="/home/leejaehyo/jobs/IMAGE"
    PATH_BEFORE="${1}"
    IMAGE_FILE_NAME="$(date +'%Y%m%d')_"

    # 디렉토리가 없을 시 해당 디렉토리를 해당 경로에 생성
    if [[ ! -d ${PATH_AFTER} ]]; then
        mkdir ${PATH_AFTER}
        echo "디렉토리 생성이 완료되었습니다"
    else 
        echo "해당 이름을 가진 디렉토리가 이미 존재합니다"
    fi

    # 정리하고 싶은 파일 리스트 가져오기
    FILE_LIST_LENG=($(ls -lh ~/jobs | awk '{print $9}' | wc -l))
    
    for idx in $(seq 0 "${FILE_LIST_LENG}")
    do
        # 파일 리스트 목록 출력 후 배열로 감싸기 (리스트 )
        FILE_LIST=($(ls -lh ~/jobs | awk '{print $9}'))
        
        # '.' 확장자를 기준으로 나누고 그것에 2번째 필드(확장자명)을 뽑아온다.
        RESULT="$(echo ${FILE_LIST[${idx}]} | awk -F'.' '{print $2}')" 
        
        # 파일 목록에 "IMAGE"나 "programming"가 존재하는 경우 continue 처리
        if [[ ${FILE_LIST[${idx}]} = "IMAGE" ]] || [[ ${FILE_LIST[${idx}]} = "programming" ]]; then 
            continue
        fi
    

        # -n : 변수에 담긴 값이 Null(빈 공백 , 또는 빈 데이터를 담고있는 변수 또는 NULL값을 담고 있는 변수)이 아닌 경우
        if [[ -n ${RESULT} ]]; then 
            mv ${PATH_BEFORE}/${FILE_LIST[${idx}]} ${PATH_AFTER}/${IMAGE_FILE_NAME}${FILE_LIST[${idx}]}
        else 
            if [[ -z ${FILE_LIST[${idx}]} ]]; then
                echo "존재하지 않는 파일입니다 🤪"
                echo
            else

                echo "${FILE_LIST[${idx}]} :: 이 파일은 확장자가 존재하지 않는 파일이므로 이동시킬 수 없습니다! 🤪"
                echo
            fi
        fi
    done
    echo "파일 이동이 끝났습니다 🤟"
    
}
 
if [[ ! ${#} -ne 1 ]]; then
    AUTOMATION_DIR ${1} # 정리하고싶은 경로 적기
else
    echo
    echo -e "스크립트 사용방법이 잘못되었습니다\n\n사용방법 :: ${0} [정리하고 싶은 디렉토리 경로]"
    exit 1
fi

DB 로그 정리

#!/usr/bin/bash

LOGDIR="/var/log/mysql"
GZIPDAY=1
DELDAY=2


/usr/bin/find "${LOGDIR}" -type f -iname "*.log" -mtime +${GZIPDAY} -exec bash -c "gzip {}" \;  2>&1
/usr/bin/find "${LOGDIR}" -type f -iname "*.gz" -mtime +${DELDAY} -exec bash -c "rm -f {}"  \;  2>&1

이메일 보내기

  • df -h 출력 결과를 이메일로 전송하기
#!/bin/bash

####################
# IFS Setting
IFS_BACK=${IFS}
#

#####################
# sudo
sudo=$(which sudo)
#

####################
# File Name
FILE="./df.log"
#

#####################
# To Email Address
TO_EMAIL="$(cat ./.address.mail | awk -F'=' '{print $2}')"
#

#####################
# Disk Free Checking
function df_checking() {
    df_leng=$(df -h | awk '{print $1}' | grep -v "[A-Z]" | wc -l)
    usages=($(df -h | awk '{print $5}' | grep -v "[A-Z]" | awk -F'%' '{print $1}'))
    mounts=($(df -h | awk '{print $6}' | grep -v "[A-Z]" | awk -F'%' '{print $1}'))

    exec 3> ${1}
    for idx in $(eval seq 0 $[ ${df_leng} - 1 ])
    do
        usage=${usages[${idx}]}
        mount=${mounts[${idx}]}
        filesystem=${filesystems[${idx}]}

        echo -e "${usage}\t${mount}%" >&3
    done
}

# Send Email Function
function send() {
    # 디스크 체킹
    df_checking ${1}

    # IFS Setting Change
    IFS='\t'

    # MAIL MSG
    EMAIL_MSG=$(cat ${1})

    # Subject
    SUBJECT="Shell Script : Disk Free Monitoring"

    # To
    TO_EMAIL="yshrim12@naver.com"

    echo "${EMAIL_MSG}" | /usr/bin/mail -s "${SUBJECT}" "${TO_EMAIL}"
}

send ${FILE}

.address.mail 파일 내용

MAIL_ADDRESS=YourEmail@.com

주기적으로 명언 가져오기

main.sh

#!/bin/bash
python=$(which python3)

quote_url='http://www.quotationspage.com/qotd.html'

check_url=$(/usr/bin/wget -nv --spider ${quote_url} 2>&1 | awk '{print $5}' ) || exit 1

if [[ ${check_url} != 200 ]]
then
 echo -e "RESPONSE ERROR! : ${check_url}"
 exit 1
fi

if [[ ! -e /tmp/quote ]]
then
 echo "Creating Quote Directory"
 /usr/bin/mkdir /tmp/quote
 echo -e "\nDone!"
fi

wget -o /tmp/quote/quote.log -O /tmp/quote/quote.html ${quote_url}

${python} parsing.py

find /tmp/daily_quote/ -iname "*.txt" -mtime +3 | xargs -I % sh -c '{echo Removing %;rm -f %}'

parsing.py

from datetime import datetime
from bs4 import BeautifulSoup as bs
import requests as rq
import os
import re

def get_soup_obj(html)-> bs:
    with open(html,'r',encoding='UTF-8') as fp:
        soup : bs = bs(fp.read(),'html.parser')
    return soup

def parsing(soup)-> Dict[str,str]:
    data : Dict[str,str] = dict()

    head : str = str(soup.select_one('div.qotdhead').text.strip()).split('-')[-1].strip()

    quotes : str = ''.join([_.text.strip() for _ in soup.select('dl > dt.quote')])

    author : str = soup.select_one('td#content dl > dd > b').text.strip()

    TEXT : str = f"{'=' * 10} Daily Quote - {head} {'=' * 10 }\n\n{quotes}\n\t\tAuthor : {author}"

    data['author'] = author.split('(')[0].strip()
    data['text'] = TEXT

    return data

def new_quote_file(data :dict)-> None:
    today : str = datetime.today().strftime('%Y%m%d')

    DIR : str = f'/tmp/daily_quote/{today}'
    os.makedirs(DIR,exist_ok=True)

    fileName : str = os.path.join(DIR,data['author'] + '.txt')

    # 파일 쓰기
    with open(fileName,'w') as fp:
        fp.write(data['text'])

    print(f'파일이 정상적으로 쓰였습니다!\n{fileName}')

def main()-> None:
    # HTML FILE
    html = '/tmp/quote/quote.html'

    # get Soup
    soup = get_soup_obj(html=html)

    # Staring Parsing
    data : Dict[str,str] = parsing(soup=soup)

    # Create New File
    new_quote_file(data=data)

if __name__ == '__main__':
    main()

디스크 모니터링

main.sh

#!/bin/bash

PWD=$(pwd)
HOST=${USER}
IP_ADDR=$(ip ad sh | grep "inet" | awk -F' ' '{print $2}' | sort | grep "/24")
TELE_FILE="${PWD}/telegram.sh"


USAGES=($(du -h / --max-depth=1 2>/dev/null | grep "G" | awk -F'G' '{print $1}' | awk -F'.' '{print $1}'))
U_PATH=($(du -h / --max-depth=1 2>/dev/null | grep "G" | awk -F'G' '{print $2}'))

for idx in ${!USAGES[@]};
do

    usage=${USAGES[${idx}]}
    path=${U_PATH[${idx}]}

    if [[ ${usage} -gt 3 ]]; then
        TEXT="${path}==>${usage}G"

        # 텔레그램 메시지 보내기
        ${TELE_FILE} "${HOST}" "${IP_ADDR}" "${TEXT}"
    fi
done

telegram.sh

# TELEGRAM TOKEN
TOKEN=''Your TOKEN"

# TELEGRAM CHAT ID
CHATID=''Your Chat ID"

# Request URL
URL="https://api.telegram.org/bot${TOKEN}/sendMessage"

function alarm() {
    # ===  Telegram 봇 관련 정보 ===
    # 날짜
    DATE=$(date +"%Y.%m.%d %H:%M")

    # 보낼 메시지 작성
    TEXT="${1}(${2}) - ${3}"

    # 메시지 보내기
    curl -s -d "chat_id=${CHATID}&text=${TEXT}" ${URL} > /dev/null

    echo "Done"
}

alarm ${1} ${2} ${3}

ssh 로 클라이언트에 특정 명령 보내기

#!/bin/bash

# 배열 정의
declare -a server_list_len
declare -a server_list

# FILE
FILE='/home/wogy12395/git/shell-script/04_ssh_command_to_client/server_list.txt'

server_list_len=$(cat  ${FILE} | wc -l)
server_list=($(cat ${FILE}))

# 0번째 인자 ~ 9번째 인자 (10개)
for idx in $(eval seq 0 $[ ${server_list_len} -1]);
do

    echo "${server_list[${idx}]}"
    ssh user@"${server_list[${idx}]}" -p 9706 "ls -alht ~/"
done

Field seperator 예제 #1

#!/bin/bash

IFS=:
users=($(cat /etc/passwd))
for user in "${users[@]}"
do
    echo ${user}
done

Field seperator 예제 #2

#!/bin/bash

# Changing the IFS value

IFS.OLD=${IFS}
IFS=$'\n'

for entry in $(cat /etc/passwd)
do
    echo "Values in ${entry} -"
    IFS=:
    for value in ${entry}
    do
        echo -e "\t${value}"
    done

    echo
done

Loop Output

#!/bin/bash

for file in ${HOME}/*
do
    if [[ -d ${file} ]]
    then
        echo "${file} is a directory"
    elif [[ -f ${file} ]]
    then
        echo "${file} is a file"
    fi
done >| output.txt

cat ./output.txt

지속적 리다이렉트 (exec)

  • exec 명령은 새로운 쉘을 시작하고 STDOUT 파일 디스크립터를 파일로 리다이렉트 함
#!/bin/bash

# redirecting output to different locations
exec 2>testerror

echo "This is the start of the script"

exec 1>testout
echo " This output should go to the testout file"
echo " but this should go to the testerror file" >&2

사용자 정의 리다이렉트

$ vim 05_script.sh

#!/bin/bash

# using an alternative file descriptor

exec 3>test13out

echo "This should display on the monitor"
echo "and this should be stored in the file" >&3
echo "Then this should be back on the monitor"

$ ./05_script.sh
-----------------------------------------------------------------------------
This should display on the monitor
Then this should be back on the monitor
-----------------------------------------------------------------------------
$ cat ./test13out
-----------------------------------------------------------------------------
and this should be stored in the file
-----------------------------------------------------------------------------

리다이렉트 활용 고급예제

#!/bin/bash
# read file and create INSERT statements for MySQL

outfile='members.sql'
IFS=','
while read lname fname address city state zip
do
    cat >> ${outfile} << EOF
    INSERT INTO member (lname,fname,address,city,state,zip) VALUES ('${lname}' , '${fname}' , '${address}' , '${city}' , '${state}' , '${zip}');
EOF
done < ${1}
done

Loading script...