如何根据原始文件的第一列值组织新文件?
Posted
技术标签:
【中文标题】如何根据原始文件的第一列值组织新文件?【英文标题】:How do I organize new files according to the first column values of the original files? 【发布时间】:2016-02-12 22:50:24 【问题描述】:假设我有 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
实际上,我有几十万个原始文件,每个文件都有几百行数据(但原始文件和新文件的总数是已知的)。实现这种排序最省时的方法是什么?
与 Fortran 之类的程序相比,Bash 脚本会是最快的方法吗?我只是在学习 sed 和 awk——这样的东西效果最好吗?
如果在链接之前提出了类似的问题,我们将不胜感激。到目前为止,我发现的 closest question 似乎表明 awk 可能是一种方法。
【问题讨论】:
“与 [...] 相比,bash 脚本会是最快的方法吗?”:否 :) 【参考方案1】:这是一个(可能非常慢)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()
既是良好做法,也是良好的可移植性建议。事实上,如果您使用大量管道,则在完成后关闭命令是必不可少的。
【讨论】:
awk 脚本是正确的方法,并且将比 shell 循环快几个数量级,但您应该提到,如果它不是 gawk,那么它需要在运行时关闭()文件或最终同时打开太多。以上是关于如何根据原始文件的第一列值组织新文件?的主要内容,如果未能解决你的问题,请参考以下文章
如何根据 Python、R 中不同数据框/患者之间的第一列元素/基因取第二列值/计数的平均值?
如何在for和if循环中获取spark scala数据帧的最后一行的第一列值