InfraPlatform

[Shell-Script 고수되기] 셀스크립트의 이해와 AWK 프로그래밍 - 디렉토리 용량 조회 ( space.sh)

IT오이시이 2024. 1. 16. 01:19
728x90


셀스크립트의 이해
셀스크립트 프로그래밍 도구 AWK

awk는 셀스크립트에서 C언어와 유사한 프로그래밍이 가능한 유용한 도구입니다.

셀스크립트의 이해와 셀스크립트를 이용한 복잡한 프로그래밍이 가능한 도구 AWK를 소개 합니다.

고수의  최강 무기 awk

예시 awk로 디렉토리별 사용량을 확인하고 소팅을 해서 출력해 주는 스크립트를 작성하는 방법을 설명합니다.

 

[첨부 파일] : "space" 스크립트 실행 방법은 아래 있습니다.

install-space2.sh
0.01MB
space
0.01MB
 

 

셀스크립트의 이해와 AWK 기초문법과 응용 -  디렉토리 사용량 조회 ( space.sh)


-
#셀스크립트문법  #awk사용법

awk를 설명하기 전에 간단한 셀스크립트 소개와 AWK의 기초 문법 그리고 세부적인 응용 문법 그리고 셀스크립트 응용 프로그램 작성등에 대한 내용으로 작성해 보았습니다.


[Shell Script 개요]


Shell Script는 Unix, Linux, Mac OS 등 같은 유닉스 시스템이 커널에 시스템을 작동하기 위한  시스템 프로그램입니다.
  쉘(Shell) 프로그래밍 언어를 사용하여 작성한  쉘 스크립트(Shell Script)로서,  운영체제에서 사용되는 커맨드 라인 인터페이스 (CLI)를 자동화하기 위해 사용됩니다.  

쉘 스크립트(Shell Script)는 일련의 명령어와 제어 구조를 포함(여러 명령을 서로 연결하여 작동)하는 텍스트 파일 입니다. 일반적으로 쉘 스크립트는 실행 가능한 파일(chmod 755 )로 만들어지고,  운영체제 쉘(/bin/bash)에서 직접 실행할 수 있습니다.



셀 스크립트  실행 방법

  
1) 기본 shell (bash) 로 직접 실행 : sh  a.sh ;    /bin/sh 라는 기본셀을 말하면 리눅스는 bash , solaris는 csh , 일부 unix ksh등 이 기본 셀로 지정되어 있음  

2) 실행 권한이 있는 셀을 직접 실행  : chmod 755 a.sh ; . /a.sh

3) 셀 스크립트의 변수를 현재의 셀로 불러오는 경우 : source  ~/.bash_profile   :  bash_profile 은  시스템 환경변수 선언용으로 사용 됩니다.
      *  .bash_profile  내부에 선언된 각종 변수, Alias,  함수 등을 선언해서 현재 셀에서 직접 불러서 사용합니다.

 

쉘 스크립트는 개발자부터 시스템을 관리자들에게 다양한  용도로 사용됩니다.


예를 들어,  배치프로그램, 파일 백업, 데이터 처리, 시스템 모니터링, 자동화된 테스트 등 여러 작업을 자동화할 수 있습니다.
쉘 스크립트는 운영체제와 관련된 다양한 작업을 수행할 수 있으며, 다른 프로그래밍 언어와 연계하여 사용될 수도 있습니다.

최근 시스템에서 작동되는 가상화 시스템(Docker), 웹서버, DB서버 등과 같이 시스템 관리나 다양한 로그를 디버깅하면서  어플리케이션을 개발하는 응용 개발자 들이라면 조금 더 shell Script의 경험이 있을 것입니다.

  오늘 소개 드리는 `space`라는  셀스크립트는 최근 클라우드 시스템을 사용하면서   여러 디렉토리 공간의 사용율을 한꺼번에 체크해야 하는 경우 효과적입니다.

요즘도 클라우드의 각 파일 시스템들을 돌아다니면서 누가 어떤 디렉토리에 어떤 일을 했는지 찾기도 어렵기 때문에  `space` 스크립트를  이용해서 각 디렉토리의 용량이나 백업 할 대상을 찾는데 활용 하면 도움이 될 것 같습니다.

 


- 셀스크립트 고수가 되기 위해 알아야하는 Awk 활용 -

[AWK를 이용한 셀스크립트 응용 예시]
   - awk를  이용한 mysql 사용자 등록 관리 sql 만들기
  - awk를 활용한 용량별 디렉토리 사용량 조회

 
 

[AWK는 C언어 처럼  프로그램을 만들 수 있어요]

Shell script 중에서 Awk는 shell script 를 이용하여 C언어  문법으로 프로그램을 구현 할 수 있다는 점이 가장 큰 장점입니다.

여기에서 Awk이 기본 문법을 모두 설명하기에는 방대한 내용이라 자세히 설명은  못해 드리지만  간단히 알아야 할  핵심 부분만 우선 정리 드립니다.

  Awk의 다양한  기능을 사용하려면  C언어 지식이 없거나 초급 Shell Script 를 만드는 분들은  C에서 사용하는 함수들과 유사함을 생각하시면 좋겠습니다.

관련된 내용은 조금씩 업데이트를 해둘 예정이오니  나중에  이런 것이 있다는 것을 기억하시면 블로그를 다시 찾아 주세요.  


[Awk 기초 정리를 알아 두시면 고수가 됩니다. ]

[Awk의 기초 문장 구조 ]
Awk의  문장 구조는  다음과 같은 4가지 영역으로 나누어 집니다.

  1) 글로벌 변수 또는 함수 를 선언 하는 영역
      - 프로그램 내부에서 필요한 변수와 함수를 정의 합니다.

  2) BEGIN {...}    : awk가 실행되면서 수행되는 영역 (데이터를 읽기전에 시작)
      - awk 는 파일을 읽으면서 한행씩 처리를 하는데 BEGIN은 읽기 전에 처리 되는 영역으로 변수 또는 초기에 필요한 내용을 작성합니다.

3) 메인 구역 { ...} : 입력 되는 데이터를 읽으면서 반복되는 영역으로  입력 값의 패턴 매칭이 가능  
      - 파일이나 입출력으로 한 행 (Line)씩 입력되는값을 반복하면서 처리하는 영역으로  특정 값을 매칭하거나 포함 되지 않은 경우를 분리해서 처리가 가능합니다.      
      - Awk의 특징중에서 C언어 처럼 if, for, while 같은 제어 흐름도 구현이 가능하지만,  C언어와 달리 특정 영역을 패턴매칭으로 분리해서  개발이 가능하다는 점입니다.
    
  4) END { ...}  : 입력 데이터를 모두 읽었고 프로그램이 종료되기 전에 수행되는 영역
  
    - 입력되는 값이 모두 처리된 마지막에 처리할 영역으로 보통 summary 데이터를 만들어 결과로 출력할 내용을 작성하는 영역입니다.  

  

Awk에서 변수와 함수를 선언하는 방법


* 아래 내용은 awk의 가장 중요한 내용이지만  이용 가이드에서 흔하지  않는 내용으로 awk를 응용하기 위해 잘 이해하시면 요긴할 것입니다.

# awk 의 영역 '  ' (single quotes) 으로  감싼 영역이 프로그램 영역입니다.
      awk  options ' { ~...~  }'  input.txt
      awk  options -f  script.awk  input.txt    : 프로그램 영역을 script.awk 로 작성해서 실행 할 수도 있습니다.


# 함수 선언
   함수선언은 function  함수명 { ..... } 으로 데이터를 처리하는  메인블록 { }  앞에 작성 합니다.

  awk 'function add(x, y) { return x + y }
          { print add($1, $2) }' input.txt
  
# 변수 선언
1. awk의 -v 옵션을 사용하여 외부 shell 변수를 전달하는 방법
  #!/bin/bash
 name="Alice"
 awk -v vanme="$name" '{ print "Hello, " vname }' input.txt

2. awk의 BEGIN 블록을 사용하여 외부 변수를 선언하는 방법
   name="Alice"
   name="Alice"
   awk 'BEGIN { vname = "'"$name"'"; print "Hello, " vname }' input.txt

3. 글로벌 변수 선언
    awk 'BEGIN { global_var = "hello" } { print global_var }' input.txt

 
 

AWK를 이용한 패턴 매칭 블록으로 처리하는 방법 (중요)

 
* 다음과 같이 각 조건의 특징을 여려 패턴 매칭으로 구분하여 처리하는 블록을 구현 할 수 있습니다.
  아래 예시는 C언어 같으면 if ... else ... 블록으로 처리를 하겠지만 awk는 패턴 매칭으로 구현을 한 경우 입니다.
 

 awk '  
      BEGIN  {  print }
             { print }
      /^aa/  { print }
     !/^aa/  { print }
   $2 ~ /bb/ { print }
   $2 != "aa" { print }
       END {  print }
       '  input.file

*  awk '{  print  } ' input.file   # 모든 행을 처리 하는경우
        
* awk '/^aa/ {  print   }'  input.file 
  #    /^aa/ {    }  : 처음 aa라는 글자로 입력되는 행의 처리

*  awk '$2 !~ /aa/ {print}' input.file
   #    $2 !~ /^aa/ {   }   :  입력값이 aa를 포함하지 않는 경우  처리

 * awk '$2 != "aa" {print}' input.file
   # 두번째 입력값이 "aa" 인경우 처리되는 영역

 
 


 [Usefull-Shell-Script] - search large directories

#셀스크립트 #shell-script #awk #du #디렉토리-용량 #파일이-많은-디렉토리-찾기 #큰-디렉토리-찾기

 

1.  awk를 활용한 유닉스 디렉토리 사이즈별 출력하기 (space.sh)

- 개발 또는 시스템 관리를 하면서 디렉토리의 파일들을 관리해야 하는 상황이 될때 용량이 많은 디렉토리를 찾거나
디스크 용량을 산정할때 사용하려고 만든 스크립트 입니다.

(199x년대에는 디스크 용량이 1GB도 많은 시절이 있었습니다. 불필요한 파일을 찾거나 파일이 많은 디렉토리를 찾고 이동하려면 일일이 파일을 찾아 보는 것도 필요해서 만든 스크립트 입니다.)

 

 

[프로그램 개요]

다음 과 같이 각 디렉토리별로 용량을 조회한 결과 페이지를  출력 하는 프로그램 입니다.

awk라는 유틸리티를 배우면서 작성했던 신입 사원 시절의 작품이기도 하고 나름 깊은 것에 심취하는 즐거움도 있었던 것 같습니다.

 

 

 

1. "space" 설치 및 사용법

[설치 / 사용법]

[install-space2.sh] 를 실행하면 "space" 라는 스크립트 파일을 자동으로 설치합니다.

[install-space2.sh 를 실행]

1. 첨부된 install-space2.sh 를 다운받아 리눅스 시스템에 저장합니다.
2. 리눅스 Root 계정으로  sh install-space2.sh 를 실행을 하면 /usr/bin/space 파일을 생성합니다.
    -  install-space2.sh는  space 라는 파일을 만드는 스크립트 입니다.

[space 파일]
3. 첨부된 "space" 파일을 다운받아  /usr/local/bin 또는 /usr/bin 에 직접 복사해도 됩니다.
     그리고 chmod 755 /usr/local/bin/space 라고 하여 실행 권한을 적용합니다.

[space 실행]
4. 사용 방법 - 다음과 같이 space 명령을 입력하고 실행합니다.
    $>  space [directory name] :
    현재 디렉토리 또는 특정 디렉토리를 지정해서 조회 가능합니다.

 

 

[사용방법]

 디렉토리의 용량 조회

  1)  space  : 옵션 값이 없으면 디폴트로 현재 디렉토리를 찾습니다.

 

 $> space          # 현재 디렉토리를 조회 합니다.

 

  2)  space  "찾을 디렉토리명"

 $> space /usr/local      # /usr/local 디렉토리를 조회합니다.

 

 

[수정사항 :]

* 2016.5.28 : 파일명 길이 큰것 반영 / 디렉토리명 Windows 환경 고려 길이 수정
* 2017.3.6 : 특정 디렉토리 사이즈 가능도록 space 명령 뒤에 디렉토리명을 입력 받음

 

 

2. 언제 사용 할 까요?

[언제 쓰면 편리 한가요 ?]

시스템 관리나 프로그램을 짜다 보면 실제 내 하위 디렉토리에 얼마만큼의 용량이 사용중인지 또는 특정 디렉토리의 용량이 많을 경우 어느 디렉토리가 많은지 일일이 찾아 본적은 없나요 ?

(디렉토리 용량이 많다는 것은 파일 수가 많거나 큰파일이 많은 경우 디렉토리 용량 관리가 필요합니다.)

 

예를 들어 특정 폴더 하위 디렉토리만 1천여개 있는 경우 어느 디렉토리가 많은 용량을 차지 하는지 체크가 필요 할때가 있습니다.
아무리 find . -size 10000k 이런 식으로 한다해도 .일일이 디렉토리를 찾아 가는 것은 힘들거나 귀찮을 겁니다.
서버 100대이상을 만지다 보면 이런 프로그램이 필요 할 때가 있습니다.

 

그리고 셀스크립트를 공부하는 분들은 이정도는 해봐야 겠지요..

반복적인 일들을 하면서 시스템 관리자들과 개발자들에게 조금이나마 보탬이 되길 바라며 적어 보았습니다.

-- Copy Right couplewith@ Choi Doo Rip Since 1999 --

를 보심 아시겠지만 상당히 오래 사용하고 수정된 것입니다.

아직 쓰는걸보면 저도 상당히 게으른 편인가요 ㅎㅎ.

 

 

3. 소스 설명

 

3.1 리눅스와 솔라이스에서도 사용 가능합니다.

 

파일명 [space] 입니다.

솔라리스와 리눅스에서 차이는 du 라는 명령 옵션이 다르므로 바꾸어 주어야 합니다.

 

[시스템 별 du 명령 ]

#for Sun Server 에서는 이것으로 쓰도록 주석을 제거하면 되구요

du -ok . 2>/dev/null | nawk -F/ -v pas=$APW '

 

#for Linux Server 에서는 이것으로 작동 됩니다.

du -Sk . 2>/dev/null | gawk -F/ -v pas=$APW

 

 

3.2 [소스] 설명

1. du 라는 명령의 출력을 이용하여 awk 이용해서 값을 합산하여 출력 합니다.
    - du는 앞에 숫자는 파일의 용량이고 뒤에는 디렉토리 하위의 파일 명을 출력합니다.

2. du의 결과를 입력 받아 전체의 디렉토리를 검색한 결과는 다음과 같습니다.
    - 아래 내용을 summary하여 소팅하고 출력합니다. 

20 ./tcd/export/home/Build/CVS
20 ./tcd/export/home/Build/lib/CVS
20 ./tcd/export/home/Build/lib/ext/CVS
16 ./tcd/export/home/Build/lib/ext/apache/CVS
12 ./tcd/export/home/Build/lib/ext/apache/apache_1.3.28/cgi-bin
276 ./tcd/export/home/Build/lib/ext/apache/apache_1.3.28/conf/ssl.crt
12 ./tcd/export/home/Build/lib/ext/apache/apache_1.3.28/conf/ssl.csr
16 ./tcd/export/home/Build/lib/ext/apache/apache_1.3.28/conf/ssl.prm
12 ./tcd/export/home/Build/lib/ext/apache/apache_1.3.28/conf/ssl.crl
28 ./tcd/export/home/Build/lib/ext/apache/apache_1.3.28/conf/ssl.key
160 ./tcd/export/home/Build/lib/ext/apache/apache_1.3.28/conf
----------------- 이하 생략 -----------

 

3. 이런 입력 값을 처음 디렉토리를 기준으로 각종 Summery 를 합니다. 
     저는 파일 개수를 카운트 하였습니다.

 

4. 그리고 입력 완료후 디렉토리의 사이즈별 소팅 과정을 거쳐 전체가 출력 됩니다.
    (내부 bubble 소트를 사용하도록 array를 이용해서 값을 소팅하고 있습니다.)

 

 

3.3 space 소스

awk에 대한 세부적인 내용은 입력으로 받은 내용을 Array로 쪼개어 넣고 소팅해서 summary를 출력하는 것인데 ..
요즘같이 클라우드 시스템을 다루는 경우에도 이런 프로그램 하나면 쓸일이 많습니다.

 
#!/bin/sh

##=======================================================================================
##
##     ----------------------------------
##      SPACE Script for Linux   V2.2
##     ----------------------------------
#
## Copy-Right
## ---------------
#  Copyright couplwith@yahoo.co.kr  Dr.choi in Seoul Korea.
#  since 2000 hanil life insurance - simmani - enkai - haansoft
#
## Update Note
## ---------------
#
# # Install guiude
#  --------------------
#   This is Shell script with awk (gawk, nawk) and du commands.
#   Using 'space' is easy find where are usage large files or space in your data storage.
#   This Script show that shell script is a good program for your system management.
#   Imagine for easy and convinence ...
#   Thank you.
#
#   For using 'space' command by followed some steps:
#   1. Requirement : linux : gawk du (cygwin) / unix nawk, gawk, du
#   2. Download and Save as  install-space.sh
#      and run install-space.sh for installation.
#        it will create : /usr/local/bin/space  and
#             chmod 755 /usr/local/bin/space
#   3. command and execute : space
#   * other wise you can copy the space file to ~/bin/space and chmod 755 ~/bin/space
#
##=======================================================================================


clear;
echo "";
echo "";
echo "";
df -k ;
APW=`pwd`
APW=${1:-`pwd`}

#for Sun Server
#du -ok . 2>/dev/null | nawk -F/ -v pas= '
#for Linux Server
#du -Sk  2>/dev/null | gawk -F/ -v pas= '
#du -Sk $APW 2>/dev/null | sed -e "s/$dpattern/./"
#   dpattern : \/usr\/local\/src

dpattern=$( echo "$APW" | sed -e 's/\//\\\//g' )

du -Sk $APW 2>/dev/null | sed -e "s/$dpattern/./" | gawk -F/ -v pas=$APW '
    BEGIN {
                    print  "\t\t------------------------------";
                    print  "\t\t DIsk Usae of current Dir V2.2";
                    print  "\t\t------------------------------";
                    printf "\t\t [%s] \n\n", pas;

                    printf"\t-------------------------------------------------------------------------------\n"
                    printf"\t%-50s : %12s   : %10s \n","DIRNAME", "SIZE (MB)","Subdir cnt";
                    printf"\t-------------------------------------------------------------------------------\n"
               tots=0;
               tcnt=0;
               i=0;
           }
           {
                pos=index($1, ".");
                if(pos > 0 ){
                    size=substr($1,1, pos-1);
                }else{
                    size=$1;
                }
                gsub(" ","" , $2);

                tcnt++;
                tots+=size;

                if ( NR ==1 )
                {
                    dirs=$2;
                    dsize=0;
                    dcnt=0;
                }

                if ( dirs == $2 )
                {
                    dsize+=size;
                    dcnt++;
                }
                else
                {
                  # printf"\t%-45s : %10.2fMB : %10d \n",dirs, dsize/1024, dcnt;
                    DIR[i]= dirs;
                    Dsize[i]=dsize/1024;
                    Dcnt[i]=dcnt;

                    dirs=$2;
                    dsize=size;
                    dcnt=1;
                    i = i + 1;
                }

            }
        END {
                    DIR[i]  = "./";
                    Dsize[i]=dsize/1024;
                    Dcnt[i]=dcnt;

                    # SORT SECTION
                    for ( j=0; j Dsize [k]){
                               tmp1=DIR[j];
                               tmp2=Dsize[j];
                               tmp3=Dcnt[j];

                               DIR[j]=DIR[k];
                               Dsize[j]=Dsize[k];
                               Dcnt[j]=Dcnt[k];

                               DIR[k]=tmp1;
                               Dsize[k]=tmp2;
                               Dcnt[k]=tmp3;
                           }
                        }
                    }

                    # PRINT SECTION
                    for ( j=0; j<=i ; j++ )
                    {
                        printf"\t%-50s : %10.2fMB : %10d \n",DIR[j], Dsize[j], Dcnt[j];
                    }
                    printf"\t-------------------------------------------------------------------------------\n"
                    printf"\t%-50s : %10.2fMB : %10d \n","TOTALSIZE", tots/1024, tcnt;
                    printf"\t-------------------------------------------------------------------------------\n"
                    printf"\t      --  Copy Right @ Choi Doo Rip  1999 09 01  --  \n"

            }'

이상 입니다.

구미에 맞게 수정 해서 쓰시고 덧글을 붙여 주세요..

 

 
[참고]
  - [Usefull-Shell-Script] awk를 활용한 디렉토리 사이즈별 검색하기 (space.sh)
     
https://blog.naver.com/couplewith/60006771096
 
 
 

728x90
반응형