好吧,问题比这更复杂一点
我有 2 个文件,比方说文件1和文件2,每个都有以下数据:
name of the game, hours spent playing it, last 7 days
文件1:
game1 100 20
game3 40 5
文件2:
game1 90 25
game4 40 2
目标:
如果两个文件中都有游戏,则减去玩游戏所花费的时间文件1 - 文件2
如果一场比赛只在文件1,显示它,但作为原始(文件1 - 0)
如果一场比赛只在文件2,显示它,但作为原始的负片(0 - 文件2)
我怎样才能做到这一点bash
?
答案1
即兴回答,假设文件已排序:
awk '{$2= -$2; $3= -$3} 1' file2 |
join -a1 -a2 file1 - |
awk 'NF > 3 {$2+=$4; $3+=$5; NF=3} 1'
提供输入的输出:
game1 10 -5
game3 40 5
game4 -40 -2
(如果文件未排序,只需对它们进行排序并保持排序即可。这会让事情变得更容易。)
请注意,这仅使用POSIX 的特点join
和Awk 的 POSIX 特性,所以它几乎可以在任何地方工作。
$2
awk 中是对第二个字段的引用。 $3
是对第三个字段(处理的文件的每一行)的引用。 1
出现在大括号之外{...}
仅意味着“true”,因此执行打印该行的默认操作。
本质上,第一个 Awk 命令只是将数字file2
变成负数。
该join
命令连接file1
到其标准输入上提供的文本(它从 Awk 接收的内容)。命令中的-
后面(而不是另一个文件名)表示“使用标准输入”。选项和意味着第一个或第二个文件中任何不可配对的行都按原样输出。file1
join
-a1
-a2
最后的 Awk 命令采用已配对的行,即氮数量Ffields 大于 3 ( NF > 3
),并将第四个字段添加到第二个字段,将第五个字段添加到第三个字段,然后截断第四个和第五个字段。
同样,最后的1
外部大括号用于触发 Awk 的默认操作“打印”。
(看本教程了解更多信息并正确学习 Awk。)
这里发生了很多事情。我建议在添加下一部分之前运行这些命令的每一部分。第一的:
awk '{$2= -$2; $3= -$3} 1' file2
并研究并理解这一点。然后:
awk '{$2= -$2; $3= -$3} 1' file2 |
join -a1 -a2 file1 -
并研究并理解这一点。 (还可以尝试省略-a1
和-a2
标志,或仅省略其中之一。)
然后使用完整命令:
awk '{$2= -$2; $3= -$3} 1' file2 |
join -a1 -a2 file1 - |
awk 'NF > 3 {$2+=$4; $3+=$5; NF=3} 1'
看看它是否更有意义。
答案2
不优雅bash
、、、join
GNU sed
变体:
join -a1 -a2 -o 0 1.2,2.2,1.3,2.3 file1 <(sed 's/ \([0-9]*\)/ -\1/g' file2) | \
sed 's/ -/-/g;s/[0-9]*-[0-9]*/$((&))/g;s/.*/echo &/eg'
输出:
game1 10 -5
game3 40 5
game4 -40 -2