ループとawkを使用して各列の最大文字長を見つける

ループとawkを使用して各列の最大文字長を見つける

ドキュメントを繰り返しながら、列内の最大文字長を見つけて返すスクリプトを作成しようとしています。私の目標は10,11,14,51ですが、スクリプトは78,78,78,78を返します。

for ((i=1;i<=4;i++)); do
  awk -F"|" '{ print length($i) }' contact_d.csv | sort -nr | sed '1!d';
done

contact_d.csv以下が含まれます:(ダミーデータを参照)とその例

Barrera|Wilkinson|(09) 1466 1886|[email protected]
Hopkins|Sellers|(07) 3814 2364|[email protected]
Hunter|Calderon|(01) 3984 0139|[email protected]

forループが私の目標を返さない理由を知っている人はいますか?

答え1

次のコードが機能します。

awk -F'|' '{for (i=1;i<=NF;i++) {len=length($i); if (len>lval[i]) {lval[i]=len; lpos[i]=FNR;}}} END{for (i in lval) printf("Longest value of column %d: %d (line %d)\n",i,lval[i],lpos[i])}' contact_d.csv

上記の例では、次を返します。

Longest value of column 1: 7 (line 1)
Longest value of column 2: 9 (line 1)
Longest value of column 3: 14 (line 1)
Longest value of column 4: 26 (line 2)
  • 各行に対して、スクリプトはすべてのフィールド(1からNFフィールド数まで)を繰り返し、フィールドの長さ(変数に一時的に保存されている)lがこれまでに見つかった最長の長さ(フィールドに保存されている)よりも大きいことを確認しますlval。 =column) 数値インデックスの下の配列変数にあります。

  • 最初の行ではlvalまだ初期化されていません。それはまるで行動するでしょうすべてlval[i]0です(実際にはそれよりも複雑です)。

  • i現在の行フィールドの長さがに格納されている値より長い場合、lval[i]スクリプトはフィールドの現在の長さlval[i]と現在の行番号(「auto」変数を介してアクセス可能FNR)を配列変数に保存しますlpos

  • ファイルの終わり(END条件)は、すべての列の最も長い長さとその場所を印刷します。ループを使用してfor (i in lval)すべての構成を確認します。索引配列に存在するため、追加変数lvalに列数を格納する必要はありません(この場合は必要ですfor (i=1;i<=ncols;i++))。ブロックでは、END「フィールド数」の概念がやや不明瞭になります。ただし、実際にはawkアクセス時にファイルの最後の行に対応する値が通常使用されます。)。

シェルループから呼び出す必要はほとんどありませんawk。ループで実行する必要があるほとんどの操作を実行できます。

最初の試行が失敗した理由は、コードが一重引用符で囲まれたスクリプト$iにシェル変数()を提供しようとしましたが(提案されているように)、一重引用符はシェル変数の解釈をオフにします。awkそうではありませんでした。対応していなかったでしょう)。

関連情報