Bashscript | 4

명상록·2023년 2월 28일
0

shell script

목록 보기
2/5

앞으로의 포스팅 진행 방향입니다. sed나 배열을 포스팅하고 싶었으나 비중을 awk에 몰고 후에 스크립트를 분석하는 것으로 몰았습니다. 스킬 향상은 상대적으로 후자에서 더 많이 보여질 것으로 예상하고 있고 분석 중 전자의 경우가 나올 때 주석이나 밑에 설명을 적으려고 합니다.

awk 정의

awk는 파일로부터 레코드(record)를 선택하고 데이터를 분류한 다음, 선택된 레코드에 포함된 값을 조작하거나 데이터화하는 것을 목적으로 사용하는 프로그램입니다. 즉, 데이터를 내가 원하는 포맷대로 쉽게 가공할 수 있도록 도와주고 그 결과를 행과 열로 출력해주는 일을 합니다.

여기서 잠깐

프로그램이라 명한 이유는 "awk programming language"라는 프로그래밍 언어로 작성된 프로그램을 실행하는 명령어이기 때문입니다.
출력 라인을 포맷, 조건 및 루프, 산술 및 문자열 연산에 이용됩니다.

이렇게만 작성하면 '그래서 정확히 어떤 일인데?' 하실 수 있습니다.

  • 파일을 한 줄씩 검사합니다.
  • 각 입력 줄을 필드로 분할합니다.
  • 파일의 특정 필드만 출력합니다.
  • 특정 필드에 연산 수행 결과를 출력하거나 필드에 문자열을 추가해서 출력합니다.
  • 입력 라인 및 필드를 패턴과 비교합니다.
  • 패턴이 포함된 레코드를 출력합니다.
  • 필드 값 비교에 따라 레코드를 출력합니다.
쉬운 이해를 위한 file.txt

흰색 박스로 묶은 부분은 레이블이 되고 레이블 안 공백(Space, Tab)을 기점으로 필드라 명명됩니다.

awk 문법과 사용 예시

awk [옵션] 패턴 {액션} [파일]
패턴과 옵션은 생략도 되고 여러 개 사용도 가능합니다. 다만
패턴을 생략하는 경우는 "모든 레코드"가 적용되고, 액션을 생략하면 "print"가 적용됩니다.

백문이 불여일견. 바로 예시로 넘어가서 설명드리겠습니다.

# pattern 생략.
$ awk '{ print }' ./file.txt      # file.txt의 모든 레코드 출력.

# action 생략.
$ awk '/j/' ./file.txt            # file.txt에서 j를 포함하는 레코드 출력
#file.txt에서는 j가 들어간 3번 도요타의 레이블이 출력됩니다.


#그렇다면 밑의 출력은 어떤 명령을 입력하여 나왔을지 한 번 생각해보세요!
Name	Country
	
KIA		Korea
Volvo	Sweden
Toyata	Japen
Ferrari	Italy
Ford	USA

# a가 들어간 라인을 카운팅한 후 출력합니다.
$ awk '/a/{++cnt} END {print "Count = ", cnt}' file.txt
# Count = 4

BEGIN/END란? END 이전의 액션과 패턴을 BEGIN, 이후의 액션을 END라 합니다.

현재 /a/{++cnt}이 BEGIN에 해당되고 BEGIN을 처리해야 END의 액션이 정상적으로 이루어집니다.


# awk를 이용해 해당 레코드의 첫 번째 열과 마지막 열을 가져와 출력합니다. 
$ df -kPF xfs | awk '/boot/ {print $1, $NF}'
/dev/nvme0n1p1 /boot

#위 명령과 차이점은 -F: 입니다. 필드 구분 문자를 공백 말고 ":" 로 설정하게 됩니다.
#직접 명령어를 입력해보면서 -F를 넣지 않았을 때 또한 보면 좋겠습니다. 
$ head -5 /etc/passwd | awk -F: '/root/ {print $1,$NF}'
root /bin/bash

#길이가 20이 넘는 레이블을 >(리다이렉션)을 이용해 result.txt에 저장합니다. 
$ awk 'length($0) > 20' file.txt > result.txt
$ cat result.txt
Item	Name	Country		cost
2		Volvo	Sweden		$4000
3		Toyata	Japen		$3000
4		Ferrari	Italy		$10000

감이 조금 잡히셨나요?

Light Question

파일을 만들어서 내용을 기입하고 output에 해당하는 결과를 얻어내는 과정을 통해 조건문을 학습하겠습니다.
조건에 따라 출력을 달리 해야하니 이를 구분하는 if가 필요하겠습니다.

# Question 1

A 25 27 50
B 35 75
C 75 78 
D 99 88 76

#output
Not all scores are available for B
Not all scores are available for C
# Question 2

A 25 27 50
B 35 37 75
C 75 78 80
D 99 88 76

#output
A : Fail
B : Fail
C : Pass
D : Pass

Question 1

	$ cat Quest1.txt | awk '(length($4)==0){print "Not all scores are available for",$1}'

Question 2

	$ awk -f Q2.awk ./Quest2.txt
	$ cat Q2.awk
    awk
    { 
    if ( $2 > 50 && $3 > 50 && $4 > 50 )
        print $1 " : Pass";
    else
        print $1 " : Fail";
    }

클론 코딩 - 실행으로 끝이 아니라 이해하는 것이 중요합니다.


$ cat disk_total.awk

BEGIN   {		
        print "\n----- STORAGE TOTAL USAGE INFO -----\n"
        }
{
        SIZE += $2;USED += $3		#BEGIN과 END 사이에 있어 BODY라고도 합니다.
}
END     {
        print "Total Capacity \t= " SIZE/1024 " Mbytes"
        print "USAGE \t\t= " USED/1024 " Mbytes"
        print "\n----- END -----\n"
        }

$ df -kPF xfs | awk -f disk_total.awk 

----- STORAGE TOTAL USAGE INFO -----

Total Capacity 	= 33762.7 Mbytes
USAGE 			= 6427.23 Mbytes

----- END -----

도움 받은 글

https://www.hackerrank.com/challenges/awk-1/problem?h_r=internal-search

https://www.linkedin.com/pulse/user-management-using-shell-script-naresh-kumar?trk=read_related_article-card_title

https://recipes4dev.tistory.com/171#36-%EC%A7%80%EC%A0%95%EB%90%9C-%ED%95%84%EB%93%9C%EC%9D%98-%EA%B0%92%EC%9D%84-%EB%8D%94%ED%95%9C-%EA%B0%92-%EC%B6%9C%EB%A0%A5-%ED%8A%B9%EC%A0%95-%ED%95%84%EB%93%9C%EC%97%90-%EB%8C%80%ED%95%9C-%ED%95%A9-%EA%B5%AC%ED%95%98%EA%B8%B0

profile
등불은 꺼질 때까지 계속해서 환하게 빛을 비춘다.

0개의 댓글