AWK 튜토리얼: Linux에서 AWK 명령의 25가지 실제 사례
Linux에서 AWK 명령을 사용하는 방법이 궁금하십니까? 다음은 AWK의 기본 사항을 익히는 데 도움이 되는 적절한 설명과 함께 25가지 AWK 명령 예제입니다.
AWK 명령은 초기 Unix 시절로 거슬러 올라갑니다. 이는 POSIX 표준의 일부이며 모든 Unix 계열 시스템에서 사용할 수 있습니다. 이후.
Perl과 같은 다목적 언어에 비해 나이가 많거나 기능이 부족하다는 이유로 때때로 신뢰를 얻지 못하지만, AWK는 여전히 일상 작업에서 사용하고 싶은 도구입니다. 때로는 상대적으로 복잡한 프로그램을 작성하는 경우도 있지만, 강력한 한 줄짜리 코드 덕분에 데이터 파일 관련 문제를 해결하기 위해 작성할 수도 있습니다.
이것이 바로 이 글의 목적입니다. 80자 미만의 문자로 AWK 기능을 활용하여 유용한 작업을 수행할 수 있는 방법을 보여줍니다. 이 기사는 완전한 AWK 튜토리얼이 아니지만 시작 부분에 몇 가지 기본 명령을 포함시켰으므로 이전 경험이 거의 또는 전혀 없더라도 핵심 AWK 개념을 이해할 수 있습니다.
이 AWK 튜토리얼에 대한 샘플 파일
해당 기사에 설명된 모든 단일 라이너는 동일한 데이터 파일에서 테스트됩니다.
cat file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
GitHub에서 온라인으로 해당 파일의 복사본을 얻을 수 있습니다.
AWK의 사전 정의된 변수와 자동 변수를 알아보세요.
AWK는 프로그램 작성에 도움이 되는 몇 가지 사전 정의된 자동 변수를 지원합니다. 그중에서 자주 접하게 될 내용은 다음과 같습니다.
RS –레코드 구분 기호. AWK는 한 번에 하나의 레코드씩 데이터를 처리합니다. 레코드 구분 기호는 입력 데이터 스트림을 레코드로 분할하는 데 사용되는 구분 기호입니다. 기본적으로 이는 개행 문자입니다. 따라서 변경하지 않으면 레코드는 입력 파일의 한 줄이 됩니다.
NR – 현재 입력 레코드 번호. 레코드에 표준 개행 구분 기호를 사용하는 경우 이는 현재 입력 줄 번호와 일치합니다.
FS/OFS –필드 구분자로 사용되는 문자. AWK가 레코드를 읽으면 이를 기반으로 여러 필드로 분할합니다. FS
의 값입니다. AWK가 출력에 레코드를 인쇄할 때 필드를 다시 결합하지만 이번에는 FS
구분 기호 대신 OFS
구분 기호를 사용합니다. 일반적으로 FS
와 OFS
는 동일하지만 필수는 아닙니다. "공백"은 둘 다의 기본값입니다.
NF – 현재 레코드의 필드 수입니다. 필드에 표준 "공백" 구분 기호를 사용하는 경우 이는 현재 레코드의 단어 수와 일치합니다.
사용 가능한 다른 표준 AWK 변수가 있으므로 자세한 내용은 특정 AWK 구현 매뉴얼을 확인하는 것이 좋습니다. 그러나 이 하위 집합은 이미 흥미로운 한 줄짜리 글을 작성하기에 충분합니다.
A. AWK 명령의 기본 사용법
1. 모든 줄을 인쇄하십시오.
이 예는 대부분 쓸모가 없지만 그럼에도 불구하고 AWK 구문에 대한 좋은 소개가 될 것입니다.
awk '1 { print }' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
AWK 프로그램은 하나 이상의 pattern { action }
문으로 구성됩니다.
입력 파일의 특정 기록(“라인”)에 대해 패턴이 비로 평가되는 경우 -0 값(AWK의 "true"와 동일), 해당 액션 블록의 명령이 실행됩니다. 위의 예에서 1
은 0이 아닌 상수이므로 각 입력 레코드에 대해 { print }
액션 블록이 실행됩니다.
또 다른 트릭은 { print }
가 명시적으로 지정하지 않을 경우 AWK에서 사용되는 기본 작업 블록이라는 것입니다. 따라서 위 명령은 다음과 같이 단축될 수 있습니다.
awk 1 file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
거의 쓸모가 없는 다음 AWK 프로그램은 입력을 소비하지만 출력에는 아무것도 생성하지 않습니다.
awk 0 파일
2. 파일 헤더 제거
awk 'NR>1' file
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
이는 명시적으로 작성하는 것과 같습니다.
awk 'NR>1 { print }' file
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
이 한 줄짜리 코드는 첫 번째 항목을 제외하고 입력 파일의 레코드를 작성합니다. 이 경우 조건은 분명히 참이 아닌 1>1
이기 때문입니다.
이 프로그램은 RS
의 기본값을 사용하므로 실제로는 입력 파일의 첫 번째 줄을 삭제합니다.
3. 범위 내에서 줄을 인쇄합니다.
이는 앞의 예를 일반화한 것일 뿐이며 &&
가 논리적 and
연산자라는 점을 제외하고는 많은 설명이 필요하지 않습니다.
awk 'NR>1 && NR < 4' file
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
4. 공백 전용 줄 제거
awk 'NF' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
AWK는 FS
변수에 지정된 필드 구분 기호를 기반으로 각 레코드를 필드로 분할합니다. 기본 필드 구분 기호는 1개 또는 여러 개의 공백 문자(공백 또는 탭이라고도 함)입니다. 이러한 설정을 사용하면 공백이 아닌 문자가 하나 이상 포함된 모든 레코드에는 필드가 하나 이상 포함됩니다.
즉, NF
가 0(“false”)인 유일한 경우는 레코드에 공백만 포함된 경우입니다. 따라서 해당 단일 라이너는 공백이 아닌 문자가 하나 이상 포함된 레코드만 인쇄합니다.
5. 빈 줄 모두 제거
awk '1' RS='' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
이 한 줄짜리 코드는 RS
가 빈 문자열로 설정된 경우 “그러면 레코드는
POSIX 용어에서 언급할 가치가 있는 빈 줄은 완전히 빈 줄입니다. 공백만 포함된 줄은 "공백"으로 간주되지 않습니다.
6. 필드 추출
이는 아마도 AWK의 가장 일반적인 사용 사례 중 하나입니다. 데이터 파일의 일부 열을 추출하는 것입니다.
awk '{ print $1, $3}' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
,
,
,
17,abhishek
여기서는 입력 및 출력 필드 구분 기호를 모두 명시적으로 쉼표로 설정했습니다. AWK는 레코드를 필드로 분할할 때 첫 번째 필드의 내용을 $1에 저장하고, 두 번째 필드의 내용을 $2에 저장합니다. 여기서는 그것을 사용하지 않지만 언급할 가치가 있는 것은 $0이 전체 기록입니다.
이 한 줄짜리 글에서는 패턴 없이 액션 블록을 사용한다는 사실을 눈치채셨을 것입니다. 이 경우 패턴은 1("true")로 가정되므로 각 레코드에 대해 액션 블록이 실행됩니다.
필요에 따라 공백 또는 공백 전용 줄에 대해 원하는 내용이 생성되지 않을 수 있습니다. 이 경우 두 번째 버전이 조금 더 나을 수 있습니다.
awk 'NF { print $1, $3 }' FS=, OFS=, file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
,
17,abhishek
두 경우 모두 명령줄에서 FS
및 OFS
에 대한 사용자 지정 값을 전달했습니다. 또 다른 옵션은 AWK 프로그램 내부의 특수 BEGIN
블록을 사용하여 첫 번째 레코드를 읽기 전에 해당 변수를 초기화하는 것입니다. 따라서 귀하의 취향에 따라 다음과 같이 작성하는 것이 더 나을 수도 있습니다.
awk 'BEGIN { FS=OFS="," } NF { print $1, $3 }' file
CREDITS,USER
99,sylvain
52,sonia
52,sonia
25,sonia
10,sylvain
8,öle
,
17,abhishek
여기서 언급할 가치가 있는 것은 마지막 레코드를 읽은 후 END
블록을 사용하여 일부 작업을 수행할 수도 있다는 것입니다. 지금 막 보게 될 것처럼요. 즉, 공백 전용 줄은 우아하게 처리되지 않기 때문에 이것이 완벽하지 않다는 것을 인정합니다. 곧 가능한 해결책을 보게 되겠지만, 그 전에 계산을 좀 해보자…
7. 열 단위로 계산 수행
AWK는 표준 산술 연산자를 지원합니다. 그리고 상황에 따라 자동으로 텍스트와 숫자 사이의 값을 변환합니다. 또한 자체 변수를 사용하여 중간 값을 저장할 수도 있습니다. 이를 통해 데이터 열에 대한 계산을 수행하는 컴팩트 프로그램을 작성할 수 있습니다.
awk '{ SUM=SUM+$1 } END { print SUM }' FS=, OFS=, file
263
또는 +=
단축 구문을 사용하는 것과 동일합니다.
awk '{ SUM+=$1 } END { print SUM }' FS=, OFS=, file
263
AWK 변수는 사용 전에 선언할 필요가 없습니다. 정의되지 않은 변수는 빈 문자열을 보유하는 것으로 간주됩니다. AWK 유형 변환 규칙에 따르면 이는 0 숫자와 같습니다. 이 기능 때문에 $1
에 텍스트(제목에), 공백이 포함되어 있거나 아무 것도 포함되어 있지 않은 경우를 명시적으로 처리하지 않았습니다. 모든 경우에 0으로 계산되며 합계를 방해하지 않습니다. 물론, 곱셈을 대신하면 얘기가 달라지겠죠. 그렇다면 해당 사례에 대한 해결책을 제안하기 위해 댓글 섹션을 사용하지 않겠습니까?
8. 비어 있지 않은 줄 수 계산
이전에 END
규칙에 대해 이미 언급했습니다. 파일에서 비어 있지 않은 줄 수를 계산하는 또 다른 가능한 응용 프로그램은 다음과 같습니다.
awk '/./ { COUNT+=1 } END { print COUNT }' file
9
여기서는 COUNT
변수를 사용하고 정규식 /./
와 일치하는 각 줄에 대해 변수를 증가시켰습니다(+=1
). 이는 적어도 하나의 문자를 포함하는 각 줄입니다. 마지막으로 END 블록은 전체 파일이 처리된 후 최종 결과를 표시하는 데 사용됩니다. COUNT
라는 이름에는 특별한 것이 없습니다. Count
, count
, n
, xxxx
또는 AWK 변수 명명 규칙을 준수하는 다른 이름을 사용할 수 있었습니다.
그런데 이 결과가 맞나요? 글쎄요, "빈" 줄에 대한 정의에 따라 다릅니다. POSIX에 따라 빈 줄만 비어 있다고 생각하면 이것이 맞습니다. 하지만 공백 전용 줄도 비어 있는 것으로 간주하고 싶습니까?
awk 'NF { COUNT+=1 } END { print COUNT }' file
8
최신 버전에서는 공백 전용 줄도 무시하는 반면, 초기 버전에서는 빈 줄만 무시했기 때문에 이번에는 결과가 다릅니다. 차이점이 보이나요? 나는 당신이 스스로 그것을 알아낼 수 있도록했습니다. 이것이 충분히 명확하지 않다면 주저하지 말고 댓글 섹션을 사용하십시오!
마지막으로, 데이터 라인에만 관심이 있고 특정 입력 데이터 파일이 주어지면 대신 다음과 같이 작성할 수 있습니다.
awk '+$1 { COUNT+=1 } END { print COUNT }' file
7
AWK 유형 변환 규칙으로 인해 작동합니다. 패턴의 단항 더하기는 숫자 컨텍스트에서 $1의 평가를 강제합니다. 내 파일에서 데이터 레코드의 첫 번째 필드에는 숫자가 포함되어 있습니다. 데이터가 아닌 레코드(제목, 빈 줄, 공백만 있는 줄)에는 텍스트가 포함되어 있거나 아무것도 포함되어 있지 않습니다. 숫자로 환산하면 모두 0이 됩니다.
최신 솔루션을 사용하면 결국 0크레딧을 보유한 사용자에 대한 기록도 삭제됩니다.
B. AWK에서 배열 사용
배열은 AWK의 강력한 기능입니다. AWK의 모든 배열은 연관 배열이므로 임의의 문자열을 다른 값과 연결할 수 있습니다. 다른 프로그래밍 언어에 익숙하다면 해시, 연관 테이블, 으로 알 수 있습니다. 사전 또는 지도.
9. AWK 배열의 간단한 예
모든 사용자의 총 크레딧을 알고 싶다고 가정해 보겠습니다. 각 사용자에 대한 항목을 연관 배열에 저장할 수 있으며, 해당 사용자에 대한 기록을 만날 때마다 배열에 저장된 해당 값을 증가시킵니다.
awk '+$1 { CREDITS[$3]+=$1 }
END { for (NAME in CREDITS) print NAME, CREDITS[NAME] }' FS=, file
abhishek 17
sonia 129
öle 8
sylvain 109
나는 이것이 더 이상 단 하나의 라이너가 아니라는 것을 인정합니다. 주로 파일이 처리된 후 배열의 내용을 표시하는 데 사용되는 for
루프 때문입니다. 이제 더 짧은 예제로 돌아가 보겠습니다.
10. AWK를 사용하여 중복 라인 식별
다른 AWK 변수와 마찬가지로 배열은 액션 블록과 패턴 모두에서 사용할 수 있습니다. 이를 활용하여 중복된 줄만 인쇄하는 한 줄짜리 코드를 작성할 수 있습니다.
awk 'a[$0]++' file
52,01 dec 2018,sonia,team
++
연산자는 C 언어 계열에서 상속된 후위 증가 연산자입니다(원저자 중 한 명인 Brian Kernighan 덕분에 AWK는 자랑스러운 멤버입니다).
이름에서 알 수 있듯이 사후 증가 연산자는 변수를 증가("add 1")하지만, 엔글로빙 표현식의 평가를 위해 해당 값을 가져온 후에만 가능합니다.
이 경우 a[$0]
를 평가하여 레코드를 인쇄할지 여부를 확인하고 결정이 내려지면 모든 경우에 배열 항목이 증가합니다.
따라서 레코드를 처음 읽을 때 a[$0]
는 정의되지 않으므로 AWK의 경우 0과 같습니다. 따라서 첫 번째 레코드는 출력에 기록되지 않습니다. 그런 다음 해당 항목은 0에서 1로 변경됩니다.
동일한 입력 레코드를 두 번째로 읽을 때 a[$0]
는 이제 1입니다. 이는 "true"입니다. 라인이 인쇄됩니다. 그러나 그 전에는 배열 항목이 1에서 2로 업데이트됩니다. 등등.
11. 중복된 줄 제거하기
이전의 한 줄짜리 코드에 따라 중복된 줄을 제거해야 할 수도 있습니다.
awk '!a[$0]++' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
유일한 차이점은 표현식의 진리값을 뒤집는 논리 연산자(!
)가 아닌 논리 연산자를 사용한다는 것입니다. 거짓이었던 것은 참이 되고, 참이었던 것은 거짓이 됩니다. 논리는 이전과 똑같이 작동하는 ++
사후 증분에 전혀 영향을 미치지 않습니다.
C. 필드 및 레코드 구분자 마법
12. 필드 구분 기호 변경
awk '$1=$1' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
해당 프로그램은 쉼표를 입력 필드 구분 기호로 사용하고 세미콜론을 출력 필드 구분 기호로 사용하도록 FS
및 OFS
변수를 설정합니다. AWK는 필드를 변경하지 않는 한 출력 레코드를 변경하지 않으므로 $1=$1
트릭을 사용하여 AWK가 레코드를 분리하고 출력 필드 구분 기호를 사용하여 다시 조립하도록 합니다.
여기서 기본 작업 블록은 { print }
라는 것을 기억하세요. 따라서 다음과 같이 더 명시적으로 다시 작성할 수 있습니다.
awk '$1=$1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
두 예제 모두 빈 줄도 제거하고 있음을 눈치챘을 것입니다. 왜? AWK 변환 규칙을 기억하세요. 빈 문자열은 "false"입니다. ” 다른 모든 문자열은 “true입니다. ” $1=$1
라는 표현은 $1
을 바꾸는 가식입니다. 그러나 이것도 표현이다. 그리고 $1
값으로 평가됩니다. 이는 빈 문자열의 경우 "false"입니다. 정말로 모든 줄을 원한다면 다음과 같이 작성해야 할 수도 있습니다.
awk '($1=$1) || 1 { print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
&&
연산자를 기억하시나요? 그것은 논리적 AND였습니다. ||
는 논리적 OR입니다. 연산자 우선순위 규칙 때문에 여기에 괄호가 필요합니다. 그렇지 않으면 패턴이 대신 $1=($1 || 1)
로 잘못 해석되었을 것입니다. 그러면 결과가 어떻게 달라졌는지 테스트해 볼 수 있는 연습을 해보겠습니다.
마지막으로, 산술에 그다지 관심이 없다면 다음과 같은 간단한 솔루션을 선호할 것입니다.
awk '{ $1=$1; print }' FS=, OFS=';' file
CREDITS;EXPDATE;USER;GROUPS
99;01 jun 2018;sylvain;team:::admin
52;01 dec 2018;sonia;team
52;01 dec 2018;sonia;team
25;01 jan 2019;sonia;team
10;01 jan 2019;sylvain;team:::admin
8;12 jun 2018;öle;team:support
17;05 apr 2019;abhishek;guest
13. 여러 공백 제거
awk '$1=$1' file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
이 프로그램은 이전 프로그램과 거의 동일합니다. 그러나 필드 구분 기호는 기본값으로 두었습니다. 따라서 여러 개의 공백이 입력 필드 구분자로 사용되지만 출력 필드 구분자로는 하나의 공백만 사용됩니다. 이는 여러 공백을 하나 공백으로 통합하는 좋은 부작용이 있습니다.
14. AWK를 사용하여 라인 결합
우리는 이미 출력 필드 구분자인 OFS
를 사용했습니다. 짐작할 수 있듯이 출력 레코드 구분 기호를 지정하는 ORS
대응 항목이 있습니다.
awk '{ print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle abhishek
여기서는 개행 문자 대신 각 레코드 뒤에 공백을 사용했습니다. 일부 사용 사례에서는 이 한 줄로 충분하지만 여전히 몇 가지 단점이 있습니다.
가장 분명한 점은 공백 전용 줄을 삭제하지 않는다는 것입니다(öle 뒤의 추가 공백은 여기에서 나옵니다). 따라서 대신 일반 정규 표현식을 사용하게 될 수도 있습니다.
awk '/[^[:space:]]/ { print $3 }' FS=, ORS=' ' file; echo
USER sylvain sonia sonia sonia sylvain öle abhishek
지금은 나아졌지만 여전히 문제가 발생할 수 있습니다. 구분 기호를 눈에 보이는 것으로 변경하면 더 명확해집니다.
awk '/[^[:space:]]/ { print $3 }' FS=, ORS='+' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek+
행 끝에 추가 구분 기호가 있습니다. 왜냐하면 필드 구분 기호는 각 레코드 뒤에 작성되기 때문입니다. 마지막 것을 포함합니다.
이 문제를 해결하기 위해 두 번째 출력 레코드부터 시작하여 레코드 앞에 사용자 정의 구분 기호를 표시하도록 프로그램을 다시 작성하겠습니다.
awk '/[^[:space:]]/ { print SEP $3; SEP="+" }' FS=, ORS='' file; echo
USER+sylvain+sonia+sonia+sonia+sylvain+öle+abhishek
구분 기호 추가는 제가 직접 처리하므로 표준 AWK 출력 레코드 구분 기호도 빈 문자열로 설정합니다. 그러나 구분 기호나 서식 지정을 시작할 때 print
문 대신 printf 함수 사용을 고려해야 한다는 신호일 수 있습니다. 지금 당장 살펴보겠지만.
D. 필드 형식 지정
나는 이미 AWK와 C 프로그래밍 언어 사이의 관계를 언급했습니다. 무엇보다도 C 언어 표준 라이브러리 AWK는 강력한 printf
기능을 상속하여 출력으로 전송되는 텍스트의 형식을 효과적으로 제어할 수 있습니다.
printf
함수는 축어적으로 출력될 일반 텍스트와 출력의 다른 섹션의 형식을 지정하는 데 사용되는 와일드카드를 모두 포함하는 형식을 첫 번째 인수로 사용합니다. 와일드카드는 %
문자로 식별됩니다. 가장 일반적인 것은 %s
(문자열 형식화용), %d
(정수 형식화용) 및 %f
(부동 소수점 숫자 형식화용)입니다. ). 이는 다소 추상적일 수 있으므로 예를 살펴보겠습니다.
awk '+$1 { printf("%s ", $3) }' FS=, file; echo
sylvain sonia sonia sonia sylvain öle abhishek
print
문과 반대로 printf
함수는 OFS
및 ORS
를 사용하지 않는다는 것을 알 수 있습니다. 가치. 따라서 구분 기호를 원할 경우 형식 문자열 끝에 공백 문자를 추가하여 명시적으로 언급해야 합니다. 이는 출력을 완전히 제어하기 위해 지불해야 하는 대가입니다.
형식 지정자는 아니지만 모든 AWK 문자열에서 개행 문자를 나타내는 데 사용할 수 있는 \n
표기법을 소개할 수 있는 좋은 기회입니다.
awk '+$1 { printf("%s\n", $3) }' FS=, file
sylvain
sonia
sonia
sonia
sylvain
öle
abhishek
15. 표 형식의 결과 생성
AWK는 구분 기호를 기반으로 레코드/필드 데이터 형식을 적용합니다. 그러나 printf
함수를 사용하면 고정 너비의 표 형식 출력을 생성할 수도 있습니다. printf
문의 각 형식 지정자는 선택적 너비 매개변수를 허용할 수 있기 때문입니다.
awk '+$1 { printf("%10s | %4d\n", $3, $1) }' FS=, file
sylvain | 99
sonia | 52
sonia | 52
sonia | 25
sylvain | 10
öle | 8
abhishek | 17
보시다시피, 각 필드의 너비를 지정하여 AWK는 해당 필드의 왼쪽을 공백으로 채웁니다. 텍스트의 경우 일반적으로 오른쪽을 채우는 것이 바람직합니다. 이는 음수 너비 숫자를 사용하여 얻을 수 있습니다. 또한 정수의 경우 공백 대신 0으로 필드를 채우는 것이 좋습니다. 이는 필드 너비 앞에 명시적인 0을 사용하여 얻을 수 있습니다.
awk '+$1 { printf("%-10s | %04d\n", $3, $1) }' FS=, file
sylvain | 0099
sonia | 0052
sonia | 0052
sonia | 0025
sylvain | 0010
öle | 0008
abhishek | 0017
16. 부동 소수점 숫자 다루기
%f
형식은 별로 설명할 가치가 없습니다...
awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%f",SUM/NUM); }' FS=, file
AVG=37.571429
... 거의 항상 표시된 결과의 필드 너비와 정밀도를 명시적으로 설정하고 싶다고 말할 수는 없습니다.
awk '+$1 { SUM+=$1; NUM+=1 } END { printf("AVG=%6.1f",SUM/NUM); }' FS=, file
AVG= 37.6
여기서 필드 너비는 6입니다. 이는 필드가 6자의 공간을 차지한다는 것을 의미합니다(점 포함, 결국에는 평소와 같이 왼쪽에 공백이 채워짐). .1 정밀도는 점 뒤에 1개의 십진수를 사용하여 숫자를 표시한다는 의미입니다. 대신 %06.1
이 무엇을 표시할지 추측해 보겠습니다.
E. AWK에서 문자열 함수 사용
printf
함수 외에도 AWK에는 다른 멋진 문자열 조작 함수가 거의 포함되어 있지 않습니다. 해당 영역에서 Gawk와 같은 최신 구현은 이식성이 떨어지는 대신 더 풍부한 내부 기능 세트를 갖습니다. 나 자신으로서는 어디에서나 동일하게 작동하는 몇 가지 POSIX 정의 함수만 다루겠습니다.
17. 텍스트를 대문자로 변환
이것은 국제화 문제를 훌륭하게 처리하기 때문에 제가 많이 사용합니다.
awk '$3 { print toupper($0); }' file
99,01 JUN 2018,SYLVAIN,TEAM:::ADMIN
52,01 DEC 2018,SONIA,TEAM
52,01 DEC 2018,SONIA,TEAM
25,01 JAN 2019,SONIA,TEAM
10,01 JAN 2019,SYLVAIN,TEAM:::ADMIN
8,12 JUN 2018,ÖLE,TEAM:SUPPORT
17,05 APR 2019,ABHISHEK,GUEST
사실 이것은 아마도 셸에서 텍스트를 대문자로 변환하는 가장 좋고 이식성이 뛰어난 솔루션일 것입니다.
18. 문자열 일부 변경
substr
명령을 사용하면 문자열을 주어진 길이로 분할할 수 있습니다. 여기서는 세 번째 필드의 첫 번째 문자만 대문자로 사용합니다.
awk '{ $3 = toupper(substr($3,1,1)) substr($3,2) } $3' FS=, OFS=, file
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,Sylvain,team:::admin
52,01 dec 2018,Sonia,team
52,01 dec 2018,Sonia,team
25,01 jan 2019,Sonia,team
10,01 jan 2019,Sylvain,team:::admin
8,12 jun 2018,Öle,team:support
17,05 apr 2019,Abhishek,guest
substr
함수는 초기 문자열, 추출할 첫 번째 문자의 (1 기반) 인덱스 및 추출할 문자 수를 가져옵니다. 마지막 인수가 누락된 경우 substr
는 문자열의 나머지 문자를 모두 가져옵니다.
따라서 substr($3,1,1)
는 $3
의 첫 번째 문자로 평가되고 substr($3,2)
는 나머지 문자로 평가됩니다. 것들.
19. 하위 필드에서 필드 분할
AWK 레코드 필드 데이터 모델은 정말 훌륭합니다. 그러나 때로는 내부 구분 기호에 따라 필드 자체를 여러 부분으로 분할하려는 경우가 있습니다.
awk '+$1 { split($2, DATE, " "); print $1,$3, DATE[2], DATE[3] }' FS=, OFS=, file
99,sylvain,jun,2018
52,sonia,dec,2018
52,sonia,dec,2018
25,sonia,jan,2019
10,sylvain,jan,2019
8,öle,jun,2018
17,abhishek,apr,2019
다소 놀랍게도 이는 일부 필드가 둘 이상의 공백으로 구분된 경우에도 작동합니다. 주로 역사적인 이유로 구분 기호가 단일 공백인 경우 split
은 "요소가 공백으로 구분되어 있습니다."라고 간주합니다. ” 그리고 단지 하나만이 아닙니다. FS
특수 변수는 동일한 규칙을 따릅니다.
그러나 일반적인 경우에는 하나의 문자열이 하나의 문자와 일치합니다. 따라서 더 복잡한 것이 필요한 경우 필드 구분 기호가 확장된 정규식임을 기억해야 합니다.
예를 들어, 콜론을 구분 기호로 사용하여 다중값 필드로 보이는 그룹 필드를 어떻게 처리하는지 살펴보겠습니다.
awk '+$1 { split($4, GRP, ":"); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team
sonia team
sonia team
sonia team
sylvain team
öle team support
abhishek guest
사용자당 최대 두 개의 그룹을 표시할 것으로 예상했지만 대부분의 경우 하나만 표시됩니다. 해당 문제는 구분 기호가 여러 번 발생하여 발생합니다. 따라서 해결책은 다음과 같습니다.
awk '+$1 { split($4, GRP, /:+/); print $3, GRP[1], GRP[2] }' FS=, file
sylvain team admin
sonia team
sonia team
sonia team
sylvain team admin
öle team support
abhishek guest
따옴표 대신 슬래시는 리터럴이 일반 문자열이 아닌 정규 표현식임을 나타내고 더하기 기호는 이 표현식이 이전 문자의 하나 또는 여러 항목과 일치함을 나타냅니다. 따라서 이 경우 각 구분 기호는 하나 또는 여러 개의 연속 콜론으로 구성됩니다.
20. AWK 명령으로 검색 및 바꾸기
정규식에 관해 말하자면, sed s///g
명령과 같은 대체를 수행하고 싶지만 한 필드에서만 수행하려는 경우가 있습니다. 이 경우 gsub
명령이 필요합니다.
awk '+$1 { gsub(/ +/, "-", $2); print }' FS=, file
99 01-jun-2018 sylvain team:::admin
52 01-dec-2018 sonia team
52 01-dec-2018 sonia team
25 01-jan-2019 sonia team
10 01-jan-2019 sylvain team:::admin
8 12-jun-2018 öle team:support
17 05-apr-2019 abhishek guest
gsub
함수는 정규 표현식을 사용하여 검색하고, 대체 문자열과 수정할 텍스트가 포함된 변수를 그 자리에서 사용합니다. 나중에 누락되면 $0으로 간주됩니다.
F. AWK에서 외부 명령 작업
AWK의 또 다른 뛰어난 기능은 외부 명령을 쉽게 호출하여 데이터를 처리할 수 있다는 것입니다. 이를 수행하는 방법에는 기본적으로 두 가지가 있습니다. system
명령을 사용하여 프로그램을 호출하고 해당 출력을 AWK 출력 스트림에 혼합하도록 하는 것입니다. 또는 파이프를 사용하면 AWK가 외부 프로그램의 출력을 캡처하여 결과를 보다 세밀하게 제어할 수 있습니다.
이것들은 그 자체로 큰 주제일 수 있지만, 다음은 이러한 기능 뒤에 숨은 힘을 보여주는 몇 가지 간단한 예입니다.
21. 파일 위에 날짜 추가하기
awk 'BEGIN { printf("UPDATED: "); system("date") } /^UPDATED:/ { next } 1' file
UPDATED: Thu Feb 15 00:31:03 CET 2018
CREDITS,EXPDATE,USER,GROUPS
99,01 jun 2018,sylvain,team:::admin
52,01 dec 2018,sonia,team
52,01 dec 2018,sonia,team
25,01 jan 2019,sonia,team
10,01 jan 2019,sylvain,team:::admin
8,12 jun 2018,öle,team:support
17,05 apr 2019,abhishek,guest
해당 AWK 프로그램에서는 UPDATED 작업을 표시하는 것으로 시작합니다. 그런 다음 프로그램은 외부 날짜 명령을 호출하여 해당 단계에서 AWK가 생성한 텍스트 바로 뒤에 결과를 출력으로 보냅니다.
AWK 프로그램의 나머지 부분은 결국 파일에 있는 업데이트 문을 제거하고 모두 인쇄합니다. 다른 줄(규칙 1
사용)
next
문을 확인하세요. 현재 레코드 처리를 중단하는 데 사용됩니다. 이는 입력 파일에서 일부 레코드를 무시하는 표준 방법입니다.
22. 외부에서 필드 수정
더 복잡한 경우에는 | AWK의 getline VARIABLE
관용구:
awk '+$1 { CMD | getline $5; close(CMD); print }' CMD="uuid -v4" FS=, OFS=, file
99,01 jun 2018,sylvain,team:::admin,5e5a1bb5-8a47-48ee-b373-16dc8975f725
52,01 dec 2018,sonia,team,2b87e9b9-3e75-4888-bdb8-26a9b34facf3
52,01 dec 2018,sonia,team,a5fc22b5-5388-49be-ac7b-78063cbbe652
25,01 jan 2019,sonia,team,3abb0432-65ef-4916-9702-a6095f3fafe4
10,01 jan 2019,sylvain,team:::admin,592e9e80-b86a-4833-9e58-1fe2428aa2a2
8,12 jun 2018,öle,team:support,3290bdef-fd84-4026-a02c-46338afd4243
17,05 apr 2019,abhishek,guest,e213d756-ac7f-4228-818f-1125cba0810f
그러면 CMD
변수에 저장된 명령이 실행되고 해당 명령 출력의 첫 번째 줄을 읽어 $5
변수에 저장됩니다.
AWK가 CMD | getline
문. close 문이 없으면 AWK는 대신 동일한 명령 인스턴스에서 여러 줄의 출력을 읽으려고 시도합니다.
23. 동적으로 생성된 명령 호출
AWK의 명령은 특별한 것이 없는 단순한 문자열입니다. 외부 프로그램 실행을 트리거하는 것은 파이프 연산자입니다. 따라서 필요한 경우 AWK 문자열 조작 함수 및 연산자를 사용하여 임의의 복잡한 명령을 동적으로 구성할 수 있습니다.
awk '+$1 { cmd = sprintf(FMT, $2); cmd | getline $2; close(cmd); print }' FMT='date -I -d "%s"' FS=, file
99 2018-06-01 sylvain team:::admin
52 2018-12-01 sonia team
52 2018-12-01 sonia team
25 2019-01-01 sonia team
10 2019-01-01 sylvain team:::admin
8 2018-06-12 öle team:support
17 2019-04-05 abhishek guest
우리는 이미 printf
함수를 만났습니다. sprintf
는 매우 유사하지만 빌드된 문자열을 출력으로 보내는 대신 반환합니다.
24. 데이터 결합
close 문의 목적을 보여드리기 위해 마지막 예를 시도해 보겠습니다.
awk '+$1 { CMD | getline $5; print }' CMD='od -vAn -w4 -t x /dev/urandom' FS=, file
99 01 jun 2018 sylvain team:::admin 1e2a4f52
52 01 dec 2018 sonia team c23d4b65
52 01 dec 2018 sonia team 347489e5
25 01 jan 2019 sonia team ba985e55
10 01 jan 2019 sylvain team:::admin 81e9a01c
8 12 jun 2018 öle team:support 4535ba30
17 05 apr 2019 abhishek guest 80a60ec8
위의 uuid
명령을 사용하는 예시와 반대로, 여기에는 od
인스턴스가 단 하나만 실행됩니다. AWK 프로그램이 실행 중이고 각 레코드를 처리할 때 동일 프로세스의 출력에서 한 줄을 더 읽습니다.
결론
AWK에 대한 빠른 둘러보기는 확실히 해당 도구에 대한 본격적인 과정이나 튜토리얼을 대체할 수 없습니다. 하지만 익숙하지 않은 분들을 위해 AWK를 도구 상자에 즉시 추가할 수 있도록 충분한 아이디어를 제공하였기를 바랍니다.
반면에, 이미 AWK 애호가라면 더 효율적으로 사용하거나 단순히 친구에게 깊은 인상을 주기 위해 사용할 수 있는 몇 가지 요령을 여기에서 찾았을 것입니다.
그러나 나는 철저한 척하지 않습니다. 따라서 모든 경우에 주저하지 말고 아래 댓글 섹션을 사용하여 좋아하는 AWK 한 줄이나 기타 AWK 팁을 공유해 주세요!