[英]How can I merge two files by column with awk?
我有以下两个文本文件:
文件 1
-7.7
-7.4
-7.3
-7.3
-7.3
文件 2
4.823
5.472
5.856
4.770
4.425
我想将它们并排合并,用逗号分隔:
文件 3
-7.7,4.823
-7.4,5.472
-7.3,5.856
-7.3,4.770
-7.3,4.425
我知道这可以通过paste -d ',' file1 file2 > file3
轻松完成,但我想要一个允许我控制每次迭代的解决方案,因为我的数据集很大,我还需要向输出添加其他列文件。 例如:
A,-7.7,4.823,3
A,-7.4,5.472,2
B,-7.3,5.856,3
A,-7.3,4.770,1
B,-7.3,4.425,1
这是我到目前为止所得到的:
awk 'NR==FNR {a[$count]=$1; count+=1; next} {print a[$count] "," $1; count+=1;}' file1 file2 > file3
输出:
-7.3,4.823
-7.3,5.472
-7.3,5.856
-7.3,4.770
-7.3,4.425
我是 bash 和 awk 的新手,因此将不胜感激:)
编辑:
假设我有一个包含成对文件的目录,以两个扩展名结尾:.ext1 和 .ext2。 这些文件的名称中包含参数,例如 file_0_par1_par2.ext1 有其对,file_0_par1_par2.ext2。 每个文件包含 5 个值。 我有一个函数可以从它的名字中提取它的序列号和它的参数。 我的目标是在单个 csv 文件 (file_out.csv) 上写入文件中存在的值以及从其名称中提取的参数。
代码:
for file1 in *.ext1 ; do
for file2 in *.ext2 ; do
# for each file ending with .ext2, verify if it is file1's corresponding pair
# I know this is extremely time inefficient, since it's a O(n^2) operation, but I couldn't find another alternative
if [[ "${file1%.*}" == "${file2%.*}" ]] ; then
# extract file_number, and par1, par2 based on some conditions, then append to the csv file
paste -d ',' "$file1" "$file2" | while IFS="," read -r var1 var2;
do
echo "$par1,$par2,$var1,$var2,$file_number" >> "file_out.csv"
done
fi
done
done
您可以将您的解决方案与“粘贴”一起使用。 例如,只需添加 while 循环即可控制每次迭代。
paste -d ',' file1 file2 | while IFS="," read -r lineA lineB;
do
# you can build new file here like you need
echo "$lineA,$lineB"
done
您的命令失败:
awk 'NR==FNR {a[$count]=$1; count+=1; next} {print a[$count] "," $1; count+=1;}' file1 file2 > file3
不要使用$count
而是count
,从 count 1 开始,在 file2 中开始时将 count 重置为 1。 最后两个条件可以通过FNR==1 {count=1}
或{count=FNR}
。
当count
始终与FNR
,为什么要使用count
?
awk 'NR==FNR {a[FNR]=$1; next} {print a[FNR] "," $1; }' file1 file2
有效地执行更新的问题所描述的方法:
假设我有一个包含成对文件的目录,以两个扩展名结尾:.ext1 和 .ext2。 这些文件的名称中包含参数,例如 file_0_par1_par2.ext1 有其对,file_0_par1_par2.ext2。 每个文件包含 5 个值。 我有一个函数可以从它的名字中提取它的序列号和它的参数。 我的目标是在单个 csv 文件 (file_out.csv) 上写入文件中存在的值以及从其名称中提取的参数。
for file1 in *.ext1 ; do
for file2 in *.ext2 ; do
# for each file ending with .ext2, verify if it is file1's corresponding pair
# I know this is extremely time inefficient, since it's a O(n^2) operation, but I couldn't find another alternative
if [[ "${file1%.*}" == "${file2%.*}" ]] ; then
# extract file_number, and par1, par2 based on some conditions, then append to the csv file
paste -d ',' "$file1" "$file2" | while IFS="," read -r var1 var2;
do
echo "$par1,$par2,$var1,$var2,$file_number" >> "file_out.csv"
done
fi
done
done
将是(未经测试):
for file1 in *.ext1; do
base="${file1%.*}"
file2="${base}.ext2"
paste -d ',' "$file1" "$file2" |
awk -v base="$base" '
BEGIN { split(base,b,/_/); FS=OFS="," }
{ print b[3], b[4], $1, $2, b[2] }
'
done > 'file_out.csv'
做base="${file1%.*}"; file2="${base}.ext2"
base="${file1%.*}"; file2="${base}.ext2"
本身比for file2 in *.ext2 ; do if [[ "${file1%.*}" == "${file2%.*}" ]] ; then
效率高 N^2 倍(给定 N 对文件) for file2 in *.ext2 ; do if [[ "${file1%.*}" == "${file2%.*}" ]] ; then
for file2 in *.ext2 ; do if [[ "${file1%.*}" == "${file2%.*}" ]] ; then
for file2 in *.ext2 ; do if [[ "${file1%.*}" == "${file2%.*}" ]] ; then
和做| awk '...'
| awk '...'
本身比| while IFS="," read -r var1 var2; do echo ...; done
效率高一个数量级| while IFS="," read -r var1 var2; do echo ...; done
| while IFS="," read -r var1 var2; do echo ...; done
| while IFS="," read -r var1 var2; do echo ...; done
(请参阅为什么使用a-shell-loop-to-process-text-thinked-bad-practice )因此您可以期望看到性能比现有脚本有巨大的改进。
两条可能有帮助的建议:
首先,我怀疑一个执行您想要的操作的 awk 脚本对于单行程序来说太长了。 我会编写一个多行脚本,将file1
和file2
作为参数,并将其存储在名为mymerge.awk
或其他文件中。 这是一个骨架:
#!/usr/bin/awk -f
BEGIN {
file1=ARGV[1]; file2=ARGV[2]
}
# The guts of your script go here.
然后您可以简单地使您的脚本可执行( chmod +x mymerge.awk
)并从 shell 调用它: mymerge.awk file1 file2
。 这种方法的优点是使您的脚本易于阅读、重用和维护。
第二条建议:使用 Awk 的getline < file1
从file1
而不是stdin
读取数据。 同样对于file2
。 要将刚刚读取的行存储在变量中,您可以说
getline var1 < file1; getline var2 < file2
Gnu Awk 用户指南对getline
及其使用方法进行了全面且易读的描述。
今晚我无法为您编写和测试工作脚本,但我希望这能帮助您取得一些进展。
awk 'BEGIN {FS=","} {getline file2_line < "file2.txt"; print $1","file2_line }' file1.txt
begin 块将字段分隔符设置为逗号,但这仅适用于 file1.txt 中的数据
脚本主体中的第一条语句将 file2.txt 中这一行的值存储到名为 file2_line 的变量中。 此变量包含 file2.txt 中的整行,并且该行中的数据不会以通常的方式拆分为字段。 这意味着如果 file2.txt 也是逗号分隔的,那么您可能希望使用 awk 的 split 函数将字符串拆分为一个数组,以便处理各个字段。
在 awk 中,通过简单地一个接一个地写入字符串值来连接,所以print $1","file2_line
写入第一个文件中的第一个字段,一个文字逗号,以及我们之前存储的 file2.txt 这一行的字符串值。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.