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 블록에 모두 인쇄할 수 있습니다.