使用 awk 将条目组织为电子表格 (csv)

使用 awk 将条目组织为电子表格 (csv)

我将条目(N= 1000)的信息保存在计算机上的分隔文本文件/每个条目中(每个条目都有一个文本文件)。记录的信息格式如下:

============
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} 会给你带来麻烦。如示例数据所示,电话号码的三组数字(以空格分隔)在 awk 中显示为 $3 $4 $5。因此,要收集整个电话号码, /PHONE:/{phone = $3 "-" $4 "-" $5} 会更合适。

相关内容