Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/18.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 如何合并两个文件并创建一个新文件,其中包含第一个文件的所有行和列,以及一个包含第二个文件的值的新列?_Bash_Awk - Fatal编程技术网

Bash 如何合并两个文件并创建一个新文件,其中包含第一个文件的所有行和列,以及一个包含第二个文件的值的新列?

Bash 如何合并两个文件并创建一个新文件,其中包含第一个文件的所有行和列,以及一个包含第二个文件的值的新列?,bash,awk,Bash,Awk,我有两个这样的文件: 文件1 文件2: a 23 100 a 24 221 a 19 454 b 45 345 b 44 344 b 10 443 c 45 190 c 98 324 我想合并这些文件以获得一个输出,其中包含第一个文件中的所有行和列,以及一个新列,如果file1和file2的第一列和第二列相等,则该列的值为file2中第三列的值,否则该列应为零。这样的输出: a 23 100 a 24 221 a 34 0 b 45 345 b 34 0 b 44 344 b 1 0 c 45

我有两个这样的文件:
文件1

文件2:

a 23 100
a 24 221
a 19 454
b 45 345
b 44 344
b 10 443
c 45 190
c 98 324
我想合并这些文件以获得一个输出,其中包含第一个文件中的所有行和列,以及一个新列,如果file1和file2的第一列和第二列相等,则该列的值为file2中第三列的值,否则该列应为零。这样的输出:

a 23 100
a 24 221
a 34 0
b 45 345
b 34 0
b 44 344
b 1 0
c 45 190
c 43 0

非常感谢。

为什么不在上面循环一下呢

F1="/path/to/File1"
F2="/path/to/File2"

while read LINE; do
  test -z "$LINE" && continue
  FOUND=$(grep -e "^$LINE " "$F2")
  test -z "$FOUND" && FOUND="$LINE 0"
  echo "$FOUND"
done < "$F1"
当然,如果文件已经排序,您可以跳过排序。

awk中的一个:

$ awk 'NR==FNR {
    a[$1 FS $2]=$3
    next
}
{
    print $1,$2,((i=a[($1 FS $2)])?i:0)
}' file2 file1
输出:

a 23 100
a 24 221
a 34 0
b 45 345
b 34 0
b 44 344
b 1 0
c 45 190
c 43 0
纯方式:
declare-afnames=();declare-a订单=()

读取字段时;do fnames[$field]=0订单+=(“$field”);完成我的答案与@JamesBrown的答案非常相似,我不打算发布它,但是@F.Hauri声称他们的shell解决方案在针对发布的输入文件运行时比awk更快,所以下面是我的awk脚本和他们的shell脚本之间的第三次运行时比较:

$ time awk 'NR==FNR{a[$1,$2]=$3; next} {print $0,a[$1,$2]+0}' file2 file1 > ou.awk

real    0m0.046s
user    0m0.000s
sys     0m0.000s

然后,我们可以清楚地看到awk脚本在执行时间上比bash脚本有了巨大的改进。两个脚本产生相同的输出值

要理解为什么shell脚本比awk脚本慢得多,请参阅上讨论的性能部分,只需google“bash associative arrays slow”或类似内容

请注意,除了运行得更快之外,awk脚本还更简洁、更清晰、更可移植,因此仅使用shell内置代码编写脚本对该任务没有任何好处。发明了shell对工具的顺序调用和操纵文件/进程的人也发明了awk,让shell调用它来进行一般用途的文本操纵,所以只需遵循他们的意图即可获得最佳结果

哦,仅供参考@JamesBrown的脚本在两个原始文件中的运行速度与我的大致相同:

$ time awk 'NR==FNR { a[$1 FS $2]=$3; next } { print $1,$2,((i=a[($1 FS $2)])?i:0) }' file2 file1 > ou.awk

real    0m0.045s
user    0m0.000s
sys     0m0.030s
以及我生成的文件:

$ time awk 'NR==FNR { a[$1 FS $2]=$3; next } { print $1,$2,((i=a[($1 FS $2)])?i:0) }' file2 file1 > ou.awk

real    0m0.066s
user    0m0.046s
sys     0m0.015s

我的文件太大(超过7000万行),所以我想这需要很多时间。@Vpers:在你的问题中,7000万行的信息丢失了。如果您认为
bash
对于7000万行来说太慢,我建议不要用
bash
标记您的问题。请参阅@EdMorton查看(我的纯文本回答)[,没有叉子,比使用
awk
!@F.Hauri的更快一些。我看了一下,你的脚本比中等大小的输入文件的awk脚本慢几个数量级。我在上发布了即使是很小的文件的计时。试试
grep-F File1 File2
@F.Hauri,它会在
b1
匹配的地方输出错误匹配例如,
b 10
。对于发布的两个输入文件,回答这个SO问题的速度更快。这似乎不太可能,因为您在循环中调用read(速度较慢)并使用bash关联数组(速度也较慢)但是在任何情况下,即使这是真的-对于小文件来说是最快的速度是没有用的,因为任何解决方案都会在一眨眼的时间内运行在小文件上。性能只对非小的输入文件有影响,而对于这样的文件,您的解决方案的运行速度将比awk解决方案慢几个数量级。我只是同时运行了awk解决方案,甚至对于小文件ion速度更快。我会将结果发布在答案中。我在上发布了这些小文件的计时,并且,至少在我的系统上,您的shell脚本比我的awk脚本慢,即使是这些小文件。[神话破灭]
$ time awk 'NR==FNR{a[$1,$2]=$3; next} {print $0,a[$1,$2]+0}' file2 file1 > ou.awk

real    0m0.046s
user    0m0.000s
sys     0m0.000s
$ cat tst.sh
#!/bin/env bash

declare -A fnames=() ; declare -a order=()
while read field;do  fnames[$field]=0  order+=("$field")  ;done <file1
while read a b c;do  fnames[$a $b]=$c                     ;done <file2
for fnam in "${order[@]}";do  echo $fnam ${fnames[$fnam]} ;done

$ time ./tst.sh > ou.bash

real    0m0.062s
user    0m0.015s
sys     0m0.030s
$ awk 'BEGIN{for (i=97; i<=122; i++) for (j=1; j<=1000; j++) printf "%c %d 27\n", i, j}' > file2

$ awk 'NR%3{print $1, $2}' file2 > file1

$ wc -l file2 file1
 26000 file2
 17334 file1
 43334 total
$ time awk 'NR==FNR{a[$1,$2]=$3; next} {print $0,a[$1,$2]+0}' file2 file1 > ou.awk

real    0m0.065s
user    0m0.031s
sys     0m0.030s

$ time ./tst.sh > ou.bash

real    0m1.674s
user    0m0.890s
sys     0m0.765s
$ time awk 'NR==FNR { a[$1 FS $2]=$3; next } { print $1,$2,((i=a[($1 FS $2)])?i:0) }' file2 file1 > ou.awk

real    0m0.045s
user    0m0.000s
sys     0m0.030s
$ time awk 'NR==FNR { a[$1 FS $2]=$3; next } { print $1,$2,((i=a[($1 FS $2)])?i:0) }' file2 file1 > ou.awk

real    0m0.066s
user    0m0.046s
sys     0m0.015s