根据文件B中的查找/替换条件,在文件A中查找和替换列中的值

时间:2018-08-16 14:42:49

标签: awk replace find

我有两个文件。第一个是FileA,它由三个列(制表符分隔)组成,请参见下面的内容

FileA

House1   dog    blue
House2   cat    yellow
House3   bird   red
House4   cow   orange
House5   duck   black 
House6   cow    brown

第二个是FileB,包含两个列(制表符分隔)FileB列1包含FileA列2中所有非常规值的列表。FileB列2包含我想要它们在Colum 1中的对应值的值的列表在FileA中替换为

FileB

dog     1
cat     2
cow     3
duck    4
bird    5 

换句话说,我希望在FileA列2中找到与FileB列1匹配的所有值,并将它们替换为File B列2中的相应值,然后将新的FileA输出到新文件(“ FileA2” )

新FileA(FileA2)的输出应如下所示(即名称栏2已全部更改为数字,每次更改都对应于FileB中的查找替换条件)

House1   1  blue
House2   2  yellow
House3   5   red
House4   3  orange
House5   4   black 
House6   3   brown

是否有awk,grep或sed单线可做到这一点?

注意:在现实生活中,我的“ FileA”在第2列中有800,000行和超过4000个唯一值,因此最好通过Linux终端来执行。

还有,是否有一种方法可以从给定文件的单个列中提取唯一值列表?

在此先感谢您的帮助。

1 个答案:

答案 0 :(得分:0)

以下应该可以解决问题(bash):

#!/usr/bin/env bash

join -t $'\t' \
    <(sort -t $'\t' -k 2 FileA) \
    <(sort -t $'\t' -k 1 FileB) \
    -1 2 \
    -2 1 | \
sort -t $'\t' -k 2 | \
awk -F '\t' 'BEGIN { OFS="\t" } {print $2, $4, $3}'

说明

首先,需要对文件进行排序以使用join命令:

sort -t $'\t' -k 2 FileA
sort -t $'\t' -k 1 FileB

在这里,我们根据第二列(FileA)对-k 2进行排序,并根据第一列(FileB)对-k 1进行排序。选项卡用于两个文件作为分隔符(-t $'\t')。

注意:可以在准备步骤中对输入进行排序(将排序后的结果存储在临时文件中),以避免在每次执行整个命令时对文件进行重新排序。

接下来,join命令将参数用作:

  • 分隔符(-t $'\t'
  • 已排序的输入(使用<(sort ...)
  • 用于连接的列:
    • -1 2 =第一个文件,第二列
    • -2 1 =第二个文件,第一列

加入后,要获得所需的输出(根据输入的第二列(包含House的列进行排序),我们需要通过运行sort -t $'\t' -k 2对上一个命令的输出进行排序

最后,awk仅用于获取所需的列(按顺序依次为第二列,第四列和第三列),并以\tBEGIN { OFS="\t" })分隔。

测试

此命令已在Linux主机上经过测试。您可以在与Docker相同的环境中测试此命令;在当前目录中,必须具有FileAFileBjoin.sh(一个包含第一个命令的可执行脚本)。

正在运行:

docker run --rm -v $(pwd):/tmp -w /tmp debian:buster ./join.sh

返回:

House1  1       blue
House2  2       yellow
House3  5       red
House4  3       orange
House5  4       black
House6  3       brown