web-dev-qa-db-ja.com

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

...その後、残りのフィールドを元の形式で印刷します。

10
Kayli O'Keefe

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
14
steeldriver

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

インテリジェントな方法は 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
terdon

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ブロックに出力できます。

1
A.Danischewski