awk를 사용하여 가변 개수의 필드가 있는 파일의 첫 번째 열 너비 수정

awk를 사용하여 가변 개수의 필드가 있는 파일의 첫 번째 열 너비 수정

awk의 printf 기능을 사용하는 방법을 이해하지만 모든 필드를 지정하고 싶지는 않습니다.

예를 들어 이것이 내 파일이라고 가정해 보겠습니다.

c1|c2|c3|c4|c5
c6|c7|c8|c9|c10
c11|c12|c13|c14|c15

각 레코드의 첫 번째 필드 너비가 c11(첫 번째 필드에서 가장 긴 셀)이 되도록 형식을 지정하고 싶습니다.

c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

다음을 지정할 수 있다는 것을 알고 있습니다.

awk -F"|" '{printf "%-3s%s%s%s%s\n", $1, $2, $3, $4, $5}' file > newfile

첫 번째 열의 너비는 알지만 파일에 필드가 몇 개 있는지 모른다고 가정해 보겠습니다. 기본적으로 다음과 같은 작업을 수행하고 싶습니다.

... '{printf "%-3s|", $1}'

...그런 다음 나머지 필드를 원래 형식으로 인쇄합니다.

답변1

sprintf재포맷 만 사용할 수 있습니다 $1.

전임자.

$ awk 'BEGIN{OFS=FS="|"} {$1 = sprintf("%-3s",$1)} 1' file
c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

답변2

첫 번째 필드의 최대/최장 길이를 파악한 다음 해당 길이를 기준으로 해당 필드의 값 형식을 다시 지정하려면 파일에 두 개의 별도 패스를 만들어야 합니다.

awk 'BEGIN     { OFS = FS = "|" }
     FNR == NR { if (m < (n=length($1))) m = n; next }
               { $1 = sprintf("%-*s", m, $1); print }' file file

(입력 파일은 명령줄에서 두 번 지정됩니다.)

귀하가 제공한 데이터의 경우

c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

첫 번째 패스는 FNR == NR블록에 의해 처리됩니다. 블록은 지금까지 표시된 가장 긴 필드(표시된 최대 길이 포함)를 추적한 m후 다음 줄로 점프합니다.

두 번째 패스는 첫 번째 필드의 형식 변경을 사용하는 마지막 블록에 의해 처리됩니다 sprintf(). 형식 문자열은 %-*s"실제 문자열을 보유하는 인수 앞의 정수 인수로 너비가 제공되는 왼쪽 정렬 문자열"을 의미합니다.

m분명히 이것은 스칼라를 각 열의 최대 너비를 유지하는 배열로 변환하여 모든 열로 확장할 수 있습니다.

$ awk 'BEGIN     { OFS = FS = "|" }
       FNR == NR { for (i=1; i<=NF; ++i) if (m[i] < (n=length($i))) m[i] = n; next }
                 { for (i=1; i<=NF; ++i) $i = sprintf("%-*s", m[i], $i); print }' file file
c1 |c2 |c3 |c4 |c5
c6 |c7 |c8 |c9 |c10
c11|c12|c13|c14|c15

답변3

현명한 방법은Steeldriver는 무엇을 제안합니까?. 불필요하게 복잡한 접근 방식은 각 필드를 반복하는 것입니다.

$ awk -F'|' '{printf "%-3s|",$1; for(i=2;i<NF;i++){printf "%s|",$i} printf "%s\n", $i}' file
c1 |c2|c3|c4|c5
c6 |c7|c8|c9|c10
c11|c12|c13|c14|c15

하지만 그렇게 sprintf $1하세요.

답변4

Awk에서는 "*"를 사용하여 동적 printf 형식 문자열을 생성할 수 있습니다.

길이를 이미 알고 있는 경우 -v를 사용하여 첫 번째 열의 필드 길이를 전달할 수 있습니다.

awk -vcol1=3 'BEGIN{FS="|"}{for(i=1;i<=NF;i++){if(i==1)printf "%*-s%s",col1,$i,FS;else if(i!=NF)printf "%s%s",$i,FS;else printf "%s\n",$i;};}' test.txt

참고: 첫 번째 열의 길이를 모르는 경우 값을 배열에 저장한 다음 최대 열 길이를 찾아 END 블록에 모두 인쇄할 수 있습니다.

관련 정보