我有七个(或八个等等)行数相同的文件。
文件1
1.001
1.002
1.003
1.004
文件2
2.001
2.002
2.003
2.004
文件3
3.001
3.002
3.003
3.004
ETC。
期望的输出:
1.001;2.001;3.001;4.001;5.001;6.001;7.001
1.002;2.002;3.002;4.002;5.002;6.002;7.002
1.003;2.003;3.003;4.003;5.003;6.003;7.003
1.004;2.004;3.004;4.004;5.004;6.004;7.004
如何在 awk 中使用简短的脚本来做到这一点?
答案1
正如 Steeldriver 所说,做到这一点的合理方法是paste
:
$ paste -d';' file*
1.001;2.001;3.001;4.001;5.001;6.001;7.001;8.001
1.002;2.002;3.002;4.002;5.002;6.002;7.002;8.002
1.003;2.003;3.003;4.003;5.003;6.003;7.003;8.003
1.004;2.004;3.004;4.004;5.004;6.004;7.004;8.004
但是,如果您必须使用awk
:
$ awk '{a[FNR]=a[FNR](FNR==NR?"":";")$0} END{for (i=1;i<=FNR;i++) print a[i]}' file*
1.001;2.001;3.001;4.001;5.001;6.001;7.001;8.001
1.002;2.002;3.002;4.002;5.002;6.002;7.002;8.002
1.003;2.003;3.003;4.003;5.003;6.003;7.003;8.003
1.004;2.004;3.004;4.004;5.004;6.004;7.004;8.004
awk 脚本将所有数据保存在内存中。如果文件很大,这可能是一个问题。但是,对于这个任务来说,paste
无论如何都更好、更简单。
怎么运行的
在此脚本中,a
有一个数组,它a[i]
是 line 的输出i
。当我们阅读每个后续文件时,我们将 line 的新信息附加i
到a[i]
.读取完文件后,我们打印出 中的值a
。更详细地说:
a[FNR]=a[FNR](FNR==NR?"":";")$0
FNR
是我们正在读取的当前文件的行号,$0
是该行的内容。这段代码添加$0
到 的末尾a[FNR]
。除非我们仍在读取第一个文件,否则我们会在 之前添加一个分号$0
。这是使用看起来复杂的三元语句来完成的:(FNR==NR?"":";")
。这实际上只是一个 if-then-else 命令。如果我们正在读取第一个文件,即 ifFNR==NR
,那么它返回一个空字符串""
。如果不是,则返回一个分号;
。END{for (i=1;i<=FNR;i++) print a[i]}
当我们读完所有文件后,这会打印出我们在 array 中积累的数据
a
。
答案2
POSIX awk;这适用于任意数量的文件,并且文件甚至不必具有相同数量的行。该脚本将继续运行,直到所有文件都超出行数:
BEGIN {
do {
br = ch = 0
while (++ch < ARGC)
if (getline < ARGV[ch]) {
printf ch < ARGC - 1 ? $0 ";" : $0 RS
br = 1
}
} while (br)
}