【问题标题】:How to delete lines containing a string that is from another file? [duplicate]如何删除包含来自另一个文件的字符串的行? [复制]
【发布时间】:2016-03-29 00:29:29
【问题描述】:

假设我有一个名为data的文件:

ID_11 0.3 0.5
ID_13 0.5 0.5
ID_14 0.6 0.3
ID_15 0.7 0.8
ID_16 0.9 1.0

我还有另一个文件ID

ID_11
ID_16

我想删除data 中第一列与ID 匹配的行。想要的输出是这样的:

ID_13 0.5 0.5
ID_14 0.6 0.3
ID_15 0.7 0.8

怎么做?

我在网上找到了一个命令。但不知道对不对。谁能解释一下?

awk 'FNR==NR{a[$1];next} !($1 in a)' ID file 

【问题讨论】:

  • 先读取ID文件,将ID作为数组的key。然后读取数据文件,检查$1是否不在数组中,打印该行。
  • @81235 -- 你已经尝试了什么?
  • 你也可以只使用grep -v -f ID data
  • 该命令看起来正确,它有效吗?
  • @Barmar。你能提供关于命令的解释吗?我对 awk 很陌生。

标签: bash awk


【解决方案1】:

你的命令对我来说很好,它也适用于我,让我解释一下命令:

$cat file1                                                                                         
ID_11 0.3 0.5
ID_13 0.5 0.5
ID_14 0.6 0.3
ID_15 0.7 0.8
ID_16 0.9 1.0
$cat file2                                                                                         
ID_11
ID_16
$awk 'NR==FNR{a[$1]++;next} !($1 in a)' file2 file1                                                
ID_13 0.5 0.5
ID_14 0.6 0.3
ID_15 0.7 0.8
  1. NR==FNR NR 是读取一个或多个文件时它保持增加的记录数,它是总文件记录数; FNR 是记录的文件编号,读取一个文件时增加,读取另一个文件时重置为0,它是当前文件记录号。

  2. a[$1]++;next 如果没有提供FS(字段分隔符),则默认分隔符是空格,在您的情况下,FS 是空格,因此无需提供。将字段 1(ID_XX) 放入数组a 作为索引号,其余跳过使用next

  3. !($1 in a)在读取第二个文件时执行,如果字段1不在数组a中,则打印出来。

【讨论】:

  • @Barmar 不完全是!有解释:)
【解决方案2】:

这部分脚本:

NR==FNR{a[$1]++;next}

将 ID 文件中的值保存到数组 a

FNR 是当前文件中的行号,NR 是所有输入文件中的行号。当它们相等时,这意味着您正在处理第一个文件。这是一个常见的习惯用法,您会在许多脚本中看到第一个文件具有特殊作用。

a[$1]++ 使用第一个字段作为数组的键并递增该数组元素。如有必要,这将创建数组元素。

next 转到输入的下一行,因此它会跳过任何其他代码块。

!($1 in a)

将在处理第二个输入文件时执行。它测试第一个字段是否不是处理第一个文件时创建的数组中的键。由于后面没有代码块,所以当测试为真时的默认操作是打印输入行。

【讨论】:

    【解决方案3】:

    你可以用 grep 做到这一点:

    $ grep -vFwf ID data
    ID_13 0.5 0.5
    ID_14 0.6 0.3
    ID_15 0.7 0.8
    

    选项执行以下操作:

    • -v: 反转匹配 - 打印 匹配的行
    • -F:固定字符串——不要将模式解释为正则表达式(这里不会改变结果,可能会加快速度)
    • -w: 单词匹配——只匹配整个单词匹配的行(避免子字符串匹配)
    • -f:从文件中读取模式——将参数解释为文件名而不是模式

    【讨论】:

      【解决方案4】:

      您可以使用join

      join -v 1 data ID
      

      默认情况下,join 使用两个文件的第一个字段。 -v 1 参数仅显示第一个文件中未配对的行。

      【讨论】:

        【解决方案5】:
        for line in $(cat ID); do sed '/$line/d' data; done
        

        我不确定如何在您的特定 shell 上完成迭代,但在上面的几行中是这样的。

        【讨论】:

        • 这是大错特错。它将多次打印数据文件,每次只跳过一行。
        • “他的特定外壳”是什么意思?问题标记为bashbash 中没有foreach 命令。
        猜你喜欢
        • 2013-05-10
        • 1970-01-01
        • 1970-01-01
        • 2014-11-30
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-11-25
        • 1970-01-01
        相关资源
        最近更新 更多