我有数以百计的全基因组关联研究文件,大约一千万行。对于file1.txt
SNP BP B SE P
123 12 0.1 0.01 0.1
...我希望在每个文件的末尾添加一个列,该列只包含该文件的名称,因此file1.txt的最终结果是:
SNP BP B SE P name
123 12 0.1 0.01 0.1 file1.txt
...我想为数百个文件做这个。目前,我可以使用以下方法添加一列:
for file in *.txt; do awk 'BEGIN{OFS="\t"}{print $0, FILENAME}' $file; done这将打印整个文件,但不会覆盖现有文件。我只想在已经存在的数据帧中添加一列。任何建议都非常感谢!
发布于 2021-06-18 17:48:11
tmp=$(mktemp) || { ret="$?"; printf 'Failed to create temp file\n'; exit "$ret"; }
for file in *.txt; do
awk 'BEGIN{OFS="\t"} {print $0, (FNR>1 ? FILENAME : "name")}' "$file" > "$tmp" &&
mv -- "$tmp" "$file" || exit
done如果您有GNU awk,并且没有超过shell参数限制的那么多文件,那么您可以只使用一个调用awk,而不需要周围的shell循环,并显式地创建临时文件(它仍然会在幕后使用临时文件,就像所有可以选择“就地”编辑的工具一样):
awk -i inplace 'BEGIN{OFS="\t"} {print $0, (FNR>1 ? FILENAME : "name")}' *.txt发布于 2021-06-18 19:52:56
如果ed可用/可接受。
for file in *.txt; do
printf '%s\n' "2,\$s|^\(.*\)\$|\1 $file|" '1s/$/ name/' 'w' 'q' | ed -s "$file"
done上面的代码需要使用最后一个字段中的name列手动调整空间。这个文件需要一个临时文件,比如@Ed_Morton所做的和column命令。
tmp=$(mktemp)
for file in *.txt; do
ed -s "$file" <<-EOF
H
2,\$s|^\(.\{1,\}\)\$|\1 $file|
1s/\$/ name/
w $tmp
,d
0r !column -t $tmp
w
Q
EOF
done警告:ed将把整个文件读入内存。
从OP的样本数据对1400万行进行测试,这一切都是好的,但更多的是错误。(YMMV)
?
Memory exhausted感谢@EdMorton指出了内存问题。
发布于 2021-06-18 22:21:02
一种sed解
建议的数据文件内容:
SNP BP B SE P
123 12 0.1 0.01 0.1用不同的文件名复制几个副本
ls
file1.dat file2.dat
cat file*
SNP BP B SE P
123 12 0.1 0.01 0.1
SNP BP B SE P
123 12 0.1 0.01 0.1循环遍历dir中的文件;
xargs或parallel可以取代for
尽快完成,但如果你有多余的资源的话,就使用更多的资源。
for f in *.dat ; do
sed -i "s/\(^SNP.*\)/\1\tname/;s/\(^[0-9].*\)/\1\t$f/g" "$f";
done 这些文件现在应该有附加的列。
cat file*
SNP BP B SE P name
123 12 0.1 0.01 0.1 file1.dat
SNP BP B SE P name
123 12 0.1 0.01 0.1 file2.dathttps://stackoverflow.com/questions/68039474
复制相似问题