awkを使用してアイテムをスプレッドシート(​​csv)として構成する

awkを使用してアイテムをスプレッドシート(​​csv)として構成する

アイテム(N = 1000)に関する情報を、アイテムごとに区切られたテキストファイル(各アイテムごとに1つのテキストファイル)としてマイコンピュータに保存します。記録される情報の形式は次のとおりです。

============
NAME: Matty Nigan
Age: 65 
Sex: M
Weight: XX
TIME: 12:31:25
Home address: XXXXX
Phone number: XXX XXX XXXX
============

次のように、これらの項目(N = 1000)からすべてのデータを収集して構成したいと思います。

NAME         AGE   SEX   Weight HOME Phone
===========
Matty Nigan  65     M    XX      XX    XX
..........
..........
..........
..........

私はこのコードを試しました:

#!/bin/bash
source=path to the folder where the entries files are.
for i in $(cat file.txt); do # file.txt is including all the delimited text files names

 awk '
 /Name:/ {name=$2}
 /Age:/ {age=$2 }
 /Sex:/ {sex=$2}
 /Home: / {home=$3}
 /Phone:/ {phone=$3}
 BEGIN { FS=":"; print "name\t\tage\t\tsex\t\thome\t\tphone:\n---------"; }       
 {print $2,"\t\t",$3,"\t\t",$4,"\t\t",$6,"\t\t",$7;}END{ print "---------\nFile Complete" }'
' ${source}/${i}| sh > outdata.csv
done

残念ながらこれはうまくいきません!何が間違っているのかわかりません。どんな助けでも大変感謝します。

答え1

awk '
BEGIN {
    fmt="%-15s%-10s%-10s%-10s%-10s%-10s\n"
    printf fmt,"Name","Age","Sex","Weight","Home","Phone"
    print "---------"
}

{
    v=$0
    sub(/[^:]*: /, "", v)
    a[$1]=v
}

/Phone/ {
    printf fmt,a["NAME:"],a["Age:"],a["Sex:"],a["Weight:"],a["Home"],a["Phone"]
    delete a
}

END{ 
    print "---------\nFile Complete" 
}' file*

列の間にダブルタブを使用すると問題があります。たとえば、長い名前と短い名前の両方がある場合、列が混在して正確に間違った場所に表示されることがあります。上記では、指定された幅で列を書式設定しました。最良の結果を得るには、幅を調整する必要があります。

これにより FS=":"問題が発生する可能性があります。フィールドには、計算に混乱を与えるコロンを含めることができます。これは、次のように最初のコロンからの情報を削除することで防ぐことができます。次の文は、すべてのファイル情報を配列としてキャプチャしますa

v=$0
sub(/[^:]*: /, "", v)
a[$1]=v

最初のフィールドはキーです。最初のコロン空白の後のすべての内容は値です。

単一のawkコマンドで複数のファイルを処理できます。上記のように、file*globと一致するすべてのファイルが処理されます。データファイルと一致するすべてのglobに置き換えます。

一度に一人ずつ処理してください。これは、コードが多くのメモリを必要としないため、大規模なデータセットに適していることを意味します。

サンプル出力

$ bash script.sh
Name           Age       Sex       Weight    Home      Phone     
---------
Matty Nigan    65        M         XX        XXXXX     XXX XXX XXXX
---------
File Complete

答え2

次のように設定されたawkを試してください。詳細を含む配列を作成し、最後に配置を印刷します。

awk -F: '
/^NAME/{name[c]=$2}
/^Age:/{age[c]=$2}
/^Sex:/{sex[c]=$2}
/^Weight:/{weight[c]=$2}
/^Home address:/{home[c]=$2}
/^Phone number:/{phone[c]=$2;c++}
END {
 print "NAME         AGE   SEX   Weight HOME Phone"
 print "==========="
 for(x in name) {
  printf "%-10s %3d    %s      %s %s %s\n",
    substr(name[x],2),
    age[x],
    sex[x],
    weight[x],
    home[x],
    phone[x]
 }
}'

答え3

また、各入力レコードに対して「{print $ 2 ...」で始まるステートメントが実行されているようです。 /PHONE:/ セレクタの後に印刷内容を中かっこで囲むことをお勧めします。また、これを行うには、BEGINセクションをそのまま追加するのではなく、プログラムヘッドに配置します。

以前のコメントで指摘したように、印刷物には$2、$3、$4などではなく、名前、年齢、性別などが必要です。

/PHONE:/ {phone=$3} が問題を引き起こすと思います。サンプルデータに示すように、電話番号の3桁の数字のセット(スペースで区切られています)はawkに$ 3 $ 4 $ 5として表示されます。したがって、電話番号全体を収集するには、/PHONE:/{phone = $3 "-" $4 "-" $5} がより適しています。

関連情報