由于来自具有 AWK 或 SED 的其他文件的变量,从文件中删除行

tit*_*ule 1 sed awk text-processing

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

我尝试了以下awk程序:

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

Adm*_*Bee 6

你已经很接近了,只是缺少一些小点:

  • 您需要将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
Run Code Online (Sandbox Code Playgroud)

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

  • FWIW 我只会在必要时重定向 awk 脚本中的输出(或输入),从而将文件操作留给最擅长的 shell。例外是我总是让 awk 打开输入文件而不是 shell(即`awk 'script' file` 而不是 `awk 'script' < file`),因为后者剥夺了你输入文件的可用性FILENAME 中的名称,并且不能扩展为具有多个输入文件。对此的权衡是,即使输入文件无法打开,`awk 'script' file > out` 也会关闭输出文件,这与 `awk 'script' < file > out` 不同。 (3认同)
  • @terdon 在 awk 中进行重定向会降低性能,因为 awk 必须知道输出文件并跟踪它是否已打开/关闭,但更重要的是恕我直言,存在功能差异 - 例如,如果您将 awk 中的输出重定向到一个不可写的文件,然后 awk 将执行其他所有操作,直到在失败之前命中该打印语句(如果您正在对 TB 文件进行计算并在 END 部分打印结果将不太理想!)而如果您将输出重定向到 awk 之外,则脚本根本不会运行。 (2认同)
  • @αғsнιη [你很接近](https://unix.stackexchange.com/questions/621506/delete-lines-from-a-file-thanks-to-variables-coming-from-an-other-file-with -awk/621564#comment1162362_621510) 但是 awk 中的 `>` 与 shell 中的 `>>` 并不完全相同,因为它并不总是在附加模式下工作。awk 中的 `>` 将在第一次写入时覆盖输出文件,然后附加到它,所以就像在 shell 中你做了 `while read foo; 做 echo "$foo"; done > file` 而不是 if 在 shell 中你做了 `while read foo; 做 echo "$foo" >> 文件;完成`。后者相当于你在 awk 中使用 `>>` 得到的。 (2认同)

ter*_*don 5

脚本中的第一个问题是:

NR == FNR {pattern[$0]; next}
Run Code Online (Sandbox Code Playgroud)

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

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

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

此外,根据您的数据,您实际上并不想检查整行。您只想跳过data.txt第二个字段与keys.txt. 如果是这样,这将更有效率,尤其是对于较大的文件:

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

或者,等效但更简洁:

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