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


10

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}'

... 그런 다음 나머지 필드를 원래 형식으로 인쇄하십시오.


그것을 해결하는 또 다른 방법 : sed 's/|/'' '' '' |/;s/\(...\) */\1/'(여기서 SE 주석이 인접한 공백을 하나로 압축 할 때 3 개의 공백을 삽입하기 위해 여분의 따옴표를 추가)
Stéphane Chazelas

답변:


14

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

간결하게, 당신은 sprintf와 함께 동적 서식을 사용할 수 있습니다 : 예awk -vf1=3 'BEGIN{OFS=FS="|"}{$1=sprintf("%-*s",f1,$1)}1' test.txt
A.Danischewski

@ A.Danischewski-음, 댕. 나는 ~ 17 년 동안 광범위한 awk 프로그래밍을 해 왔으며 이전에는 결코 그 적이 없었습니다. 모든 번거 로움을 생각하면 저를 구했을 것입니다.
Paul Sinclair

6

첫 번째 필드의 최대 / 최장 길이를 파악한 다음 해당 길이에 따라 필드의 값을 다시 형식화하려면 파일에 대해 두 개의 개별 패스를 수행해야합니다.

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

1

지능적인 방법은 스틸 드라이버가 제안한 것 입니다. 불필요하게 복잡한 방법은 모든 필드를 반복하는 것입니다.

$ 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끝내십시오.


1
당신은 그것을 약간 뒤로하고, 작은 간결한 진술은 일반적으로 더 복잡합니다. 필드를 반복하는 것은 덜 복잡합니다.
A.Danischewski

1

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.