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

最初のフィールドの最大/最長の長さを特定し、その長さに基づいてそのフィールドの値の形式を再指定するには、ファイルに2つの別々のパスを作成する必要があります。

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

(入力ファイルはコマンドラインで2回指定されます。)

あなたが提供したデータの場合

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

最初のパスはFNR == NRブロックによって処理されます。ブロックは、これまでに示された最も長いフィールド(表示された最大長を含む)を追跡し、m次の行にジャンプします。

2番目のパスは、最初のフィールドのフォーマット変更を使用する最後のブロックによって処理されます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ブロックにすべて印刷できます。

関連情報