使用 AWK 或 SED 从其他文件中删除变量,从而删除文件中的行

使用 AWK 或 SED 从其他文件中删除变量,从而删除文件中的行

我想删除data.txt包含文件中第二列参数之一的每一行keys.txt

  • keys.txt
    2 aa
    2 bb
    2 cc
    2 dd
    
  • data.txt
    1 aa It is great
    1 aa I want to delete this line
    1 kk Really ?
    1 bb Yes, I think so.
    1 bb Why ?
    1 kk Because I don't like the current situation
    1 ll I want to change
    1 cc Indeed it's a need
    1 cc Sorry
    1 zz Ok !
    
  • 所需输出
    1 kk Really ?
    1 kk Because I don't like the current situation
    1 ll I want to change
    1 zz Ok !
    

我尝试使用以下awk程序:

awk '
    NR == FNR {pattern[$0]; next}
    {
        for (var in pattern) {
            if ($0 ~ var) {
                getline
                next
            }
        }
        print >> GoodFile.txt
    }
' keys.txt

答案1

你已经很接近了,只遗漏了一些小点:

  • 您需要将data.txt其作为参数添加到您的awk调用中,否则该文件将不会被处理。
  • 您当前正在将整行注册keys.txt到删除数据库中,因此您应该将其限制为第二个字段($2而不是$0)。
  • 您用于检查是否应排除if ($0 ~ var)一行。data.txt在这里,您也应该只比较该行的第二个字段,并且应该使用精确匹配 ( ==) 而不是正则表达式匹配,以防止键可能包含正则表达式特有的字符的情况。
  • 您从 打印awk,但实际上不需要。您可以改为重定向输出。

因此,稍微修改一下:

awk 'NR==FNR{pattern[$2];next} !($2 in pattern)' keys.txt data.txt > GoodFile.txt

keys.txt这将在数​​组中注册每行的第二列pattern,但对该文件不执行任何其他操作。对于,它将达到对每条线评估条件data.txt的点。!($2 in pattern)如果条件评估为“true”(即该行的第二列是不是在数组的索引中pattern),将打印当前行。

答案2

您的脚本中的第一个问题是:

NR == FNR {pattern[$0]; next}

您使用整行作为数组的键pattern,但您只需要第二个字段。您不需要同时使用nextgetline,您只需next移至下一行即可。您还忘记传递第二个文件作为输入。最后,您需要引用文件名,因为它只是一个字符串,而不是变量。修复这两个错误会产生:

awk '
    NR == FNR {pattern[$2]; next}
    {
        for (var in pattern) {
            if ($0 ~ var) {
                getline
                next
            }
        }
        print >> "GoodFile.txt"
    }
' keys.txt data.txt

现在,你是当然你想要>>那里吗?这意味着awk不会覆盖文件中已有的任何内容(例如,先前运行的输出)。>>如果您只想awk不覆盖单次运行的输出,则不需要>就足够了。仅>>当您想保留以前运行的数据时才需要,但我怀疑您不需要。

另外,根据您的数据,您实际上不想检查整行。您只想跳过data.txt第二个字段与 中的第二个字段相同的行keys.txt。如果是这样,这会更有效,特别是对于较大的文件:

awk '
    NR == FNR {pattern[$2]; next}
    {
        if ($2 in pattern) {
            next
        }
        print > "GoodFile.txt"
    }
' keys.txt data.txt

或者,等效但更简洁:

awk '
    NR == FNR {pattern[$2]; next}
    {
        if (!($2 in pattern) {
            print > "GoodFile.txt"
        }
    }
' keys.txt data.txt

答案3

GNU sed扩展正则表达式模式打开-E,自动打印模式空间关闭-n

$ sed -En '
    /^\S+\s+(\S+)$/{
      s//\1/;H;d
    }
    G
    /^\S+\s+(\S+)\s.*\n\1(\n|$)/!P
' keys.txt data.txt

假设密钥文件有两个字段,数据文件有两个以上。

第一步,我们将keys.txt 文件的第二个字段存储在hold 中。然后,在读取 data.txt 文件时,我们将键附加到 data.txt 文件的当前记录,并比较数据的第二个字段是否可以在键中的任何位置看到。仅当未找到时,我们才会打印数据。

相关内容