假设我有3个文件:File-A
,File-B
,File-C
;其中每个文件有两列数据(空格描绘)但行数未知(和可变)。
输入
File-A:
1 dE
1 dF
2 dF
2 dH
File-B:
1 dI
3 dJ
3 dK
File-C:
2 dF
3 dH
3 dJ
3 dK
4 dL
如何有效地对数据进行排序,以便为第一列中的每个值创建新文件(即File-1
,File-2
,File-3
,File-4
)跟踪他们的第二列合作伙伴数据和原始文件名?
所需输出
File-1:
A dE
A dF
B dI
File-2:
A dF
A dH
C dF
File-3:
B dJ
B dK
C dH
C dJ
C dK
File4:
C dL
实际上,我有几十万个原始文件,每个文件都有几百行数据(但原始文件和新文件的总数是已知的)。什么是实现这种类型排序的最有效方法?
Bash脚本是否是最快的方法而不是像Fortran这样的程序?我只是学习sed和awk - 这样的工作效果最好吗?
如果在链接受到赞赏之前提出了类似的问题。到目前为止我发现的closest question似乎表明awk可能是一种可行的方式。
答案 0 :(得分:2)
这是一个(可能很慢)Bash解决方案:
#!/bin/bash
for suffix in "${@##*-}"; do # Get suffix from each file name
while read -r col1 col2; do # Read two columns
# Assemble output line and write to proper file
printf "%s %s\n" "$suffix" "$col2" >> "File-$col1"
done < "File-$suffix"
done
Bash循环很慢,许多重定向都很慢,但我无法想到另一种方法,因为每个输入行都可能转到另一个输出文件。
awk中可能更快的东西:
#!/usr/bin/awk -f
# For each new file, get the file name suffix
FNR == 1 {
split(FILENAME, arr, "-")
suffix = arr[2]
}
# On each line, create the output file name, then print to that file
{
ofname = "File-" $1
print suffix, $2 > ofname
}
使用./scriptname File-*
从命令行调用两者。
限制打开文件句柄的数量
可以同时打开多少个文件句柄是有限制的:来自您的操作系统和来自awk。 Gawk做了一些诡计 1 来解决这个问题,但是为了避免打开过多的文件句柄,它可能仍然会更快(并且更加便携)。
例如,一种补救方法是跟踪每个输入文件的打开文件句柄,然后在处理下一个文件之前关闭它们:
#!/usr/bin/awk -f
# For each new file, get the file name suffix
FNR == 1 {
# Close open files
for (fname in openfiles)
close(openfiles[fname])
split(FILENAME, arr, "-")
suffix = arr[2]
}
# On each line, create the output file name, then print to that file
{
ofname = "File-" $1
openfiles[ofname] = 1 # Keep track of open files
print suffix, $2 > ofname
}
1 来自manual:
如果您使用的文件多于系统允许您打开的文件,
gawk
会尝试在您的数据文件中复用可用的打开文件。gawk
执行此操作的能力取决于操作系统的功能,因此可能并不总是有效。因此,在完成文件后,始终对文件使用
close()
是一种良好的做法和良好的可移植性建议。实际上,如果您使用大量管道,则必须在完成后关闭命令。