我将条目(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} 会更合适。