AWK 로 DATE 및 TIME 정규표현식

Seongkeun·2022년 12월 1일
1

Linux

목록 보기
7/7
post-thumbnail

서론

데이터를 만지는데 awk 를 이용하면 다른 것보다 가볍고 빠르다. awk정규표현식과 결합해서 사용하면 정말 빠르게 작업할 수 있다. 하지만 사용법을 잘 모르면 정말 많이 헤메게 된다. 검색해도 잘 나오지 않고 혼자 이 것, 저 것 만져볼 수 밖에 없을따름이다. 이번에는 awk 를 사용하면서 정말 많이 헤맸던 코드를 작성하겠다

Task

date&time 형식에서 특정 시간 이후 데이터만을 추출하기

randomDate.csv

datecolumn1column2
2022-10-01 05:10:16aaaAAA
2022-10-02 03:16:20bbbBBB
2022-10-03 07:30:59cccCCC
2022-10-04 16:51:10dddDDD
2022-10-05 02:01:37cccCCC

위 데이터의 date 포맷을 보면 YYYY-mm-dd HH:MM:SS 형식인 것을 알 수 있다 날짜와 시간 사이에는 <공백> 이 존재한다

이 데이터를 06시 이후 데이터만을 추출할 수 있게 정규표현식awk 를 사용해서 가공해 주려고 한다

원하는 결과

datecolumn1column2
2022-10-03 07:30:59cccCCC
2022-10-04 16:51:10dddDDD

정규표현식

reg="(([12][[:digit:]]{3})-)((0[1-9]|1[0-2])-)((0[1-9]|[12][0-9]|3[01])[[:space:]])((0[6-9]|1[0-9]|2[0-3]):)((0[1-9]|[1-5][0-9]):)(0[1-9]|[1-5][0-9])"

위 형식이 이해가 가는가??? 보기가 쉽지는 않다. 하지만 하나씩 풀어보면 이해가 갈 것이다 여기에서 저 [[:space:]] 때문에 조금 헤맸었다

  1. (([12][[:digit:]]{3})-) 형식 : YYYY-
    : 1과 2로 시작하고 뒤에 오는 숫자는 3개만 가능 ( 그리고 그 뒤에 "-" )

    [예시]
    1990- (O),
    2456- (O),
    1992 (X),
    120- (X),
    0148- (X)

  1. ((0[1-9]|1[0-2])-) 형식 : mm-
    : 앞에 0이 올 땐 뒤 숫자 1~9 까지 가능, 1이 올 땐 뒤 숫자 0~2 까지 가능 ( 그리고 그 뒤에 "-" )

    [예시]
    12- (O),
    01- (O),
    11 (X),
    13- (X),
    00- (X)

  1. ((0[1-9]|[12][0-9]|3[01])[[:space:]]) 형식 : dd<공백>
    : 앞에 0이 올 땐 뒤 숫자 1~9 까지 가능, 1과 2가 올 땐 뒤 숫자 0~9 까지 가능, 3이 올 땐 뒤 숫자 0과 1 가능 ( 그리고 그 뒤에 " "(공백) )

    [예시]
    31<공백> (O),
    01<공백> (O),
    16 (X),
    32<공백> (X),
    00<공백> (X)

  1. 그리고 그 뒤 시간 형식은 앞에 말했던 형식 되짚어보면서 보면 간단히 알아볼 수 있을 것이다. 더 설명 안 하는 것은 절대 귀찮아서 그런거다. 헿

AWK

아직 bash shell script 자체가 익숙한 것이 아니라서 커맨드간의 차이를 잘 모른다 그래서 awk 를 사용해야 할 지 sed 를 사용해야 할지 많이 검색해 봤다 차이점은 sed행 단위로 편집할 수가 없는 것 같다 awk 는 sql 사용하듯이 사용 가능하다 물론 그 둘의 차이점도 존재한다


awk [옵션] [출력] [불러올파일] : awk 일반 형식

awk -F "," -v reg=${reg} '$1 ~ reg' ./awkTest.csv : 사용할 코드

정말 유의해야 할 것은 $1 ~ reg 에서 reg 앞에 $ 를 절대로 붙이면 안된다 ! 이 것 때문에 정말 오랫동안 헤맸다 !! ㅜㅜ
bash 를 사용하다보면 변수앞에 $를 넣지 않는 것을 상상하지도 못 하기 때문이다 !


아무튼 !!awk 옵션을 대충 보자면

-F : 어떤 구분자로 칼럼을 구분할 것인지? 나는 당연히 csv 파일이니 "," 로 구분한다

-v : awk 는 외부변수를 사용하려면 이 와 같은 옵션을 같이 사용해 주어야 한다 awk 로 사용하는 reg변수에 외부변수 reg 를 넣어 주었다

$1 : 첫 번째 칼럼에 대해서

~ : 정규표현식을 사용하겠다 그 뒤에 reg(정규표현식) 기입 !
--> 위 정규표현식에 해당하는 rows가 출력 됨
--> 만약 위 정규표현식에 해당하지 않는 rows 가 출력되기를 원하면 !~ 로 바꿔주면된다

예시

#!/bin/bash

customRegular="(([12][[:digit:]]{3})-)((0[1-9]|1[0-2])-)((0[1-9]|[12][0-9]|3[01])[[:space:]])((0[6-9]|1[0-9]|2[0-3]):)((0[1-9]|[1-5][0-9]):)(0[1-9]|[1-5][0-9])"

awk -F "," -v reg=${customRegular} '$1 ~ reg' ./randomDate.csv | head -n 50

위와 같이 작성하면 정규표현식에 해당하는 가장 위 50개 데이터가 출력 된다.


같이 알아두면 좋을 것 같은 sentence

sed -n '2,$p' ./randomDate.csv # 2번째 행 ~ 끝행까지 출력
sed -n '1p' ./randomDate.csv # 첫행만 출력
sed -n -e '1p' -e '10,$p' ./randomDate.csv # 1번행 출력, 10번 행 ~ 끝행까지 출력
sed -n '/^aa/p' ./randomDate.csv # aa로 시작하는 행들 출력
sed -n '/bb/p' ./randomDate.csv # bb 를 포함하는 행들 출력
sed '3d' ./randomDate.csv # 3번째 라인 삭제하고 출력
sed '3,$d' ./randomDate.csv # 3행 ~ 마지막행까지 삭제하고 출력
sed '5,10s/ccc//' ./randomDate.csv # 5~10행 중 ccc를 삭제 (원본파일이 바뀌지는 않음)

head -n 10 ./randomDate.csv | sed '2,$p'  # head 데이터 중 2행부터 끝까지 출력

REFERENCE

profile
지혜는 지식에서 비롯된다

0개의 댓글