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つのスペースを挿入するために、余分な引用符を追加)
ステファン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プログラミングを行っており、これまでに遭遇したことはありません。すべての面倒を考えると、それは私を救ったでしょう。
ポールシンクレア

6

最初のフィールドの最大/最長の長さを把握し、その長さに応じてフィールドの値を再フォーマットするには、ファイルに対して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

1

インテリジェントな方法は、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です。


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.