【问题标题】:“sed” command to remove a line that matches an exact string on first word“sed”命令删除与第一个单词上的确切字符串匹配的行
【发布时间】:2018-08-30 01:31:08
【问题描述】:

我在这里找到了我的问题的答案:"sed" command to remove a line that match an exact string on first word

...但仅部分是因为该解决方案仅在我查询与回答的人所回答的答案完全相同的情况下才有效。

他们回答:

 sed -i "/^maria\b/Id" file.txt

...仅删除以“maria”开头的一行,如果不是第一个单词,则不删除maria。

我想删除文件中的特定 url,例如:“cnn.com” - 但是,我也有一堆本地主机地址,0.0.0.0 并且都有一些前面有一个空格。我也不想删除 ads.cnn.com 之类的子域,以便代码“应该”工作,但当我使用 -e 选项输入更多命令时不会。我下面的代码似乎可以很好地清理东西,只是我无法让它破坏 cnn.com!我的文件名为 raw.txt

 sed -r -e 's/^127.0.0.1//' -e 's/^ 127.0.0.1//' -e 's/^0.0.0.0//' -e 's/^ 0.0.0.0//' -e '/#/d' -e '/^cnn.com\b/d' -e '/::/d' raw.txt | sort | tr -d "[:blank:]" | awk '!seen[$0]++' | grep cnn.com

当我 grep 搜索 cnn.com 时,我看到了所有 cnn,包括我不想要的那个实际上是“cnn.com”。

 ads.cnn.com
 cl.cnn.com
 cnn.com <-- the one I don't want
 cnn.dyn.cnn.com
 customad.cnn.com
 gdyn.cnn.com
 jfcnn.com
 kermit.macnn.com
 metrics.cnn.com
 projectcnn.com
 smetrics.cnn.com
 tiads.sportsillustrated.cnn.com
 trumpincnn.com
 victory.cnn.com
 xcnn.com

如果我只是将那一段代码与 cnn.com 一起使用,它似乎可以工作。

 sed -r '/^cnn.com\b/d' raw.txt | grep cnn.com
 * I'm not using the "-e" option

结果:

 ads.cnn.com
 cl.cnn.com
 cnn.dyn.cnn.com
 customad.cnn.com
 gdyn.cnn.com
 jfcnn.com
 kermit.macnn.com
 metrics.cnn.com
 projectcnn.com
 smetrics.cnn.com
 tiads.sportsillustrated.cnn.com
 trumpincnn.com
 victory.cnn.com
 xcnn.com

当我将命令与“-e”选项串在一起时,我所做的一切似乎都不起作用。我需要一些帮助才能让我的多选项命令与 SED 一起发挥作用。

有什么建议吗?

Ubuntu 12 LTS 和 16 LTS。
sed (GNU sed) 4.2.2

【问题讨论】:

  • 对于 SO 的挫折感到抱歉。如果你具体到你需要什么,我发现它对问题很有帮助。对于此类问题,值的示例列表以及您想要的结果将非常有帮助。话虽这么说,这里有很多信息可以得出一个非常彻底的答案。
  • 这适用于您的示例sed -re '{/#/d; /^cnn\.com\b/d; /::/d; s/^( ?(127\.0\.0\.1|0\.0\.0\.0))// }'
  • 当您发现自己在使用多个 seds 和 trs 以及 greps 和 awks 的管道时......只需将其重写为一个简单的 awk 脚本即可。

标签: regex bash shell sed


【解决方案1】:

. 是正则表达式中的元字符,意思是“匹配任何一个字符”。所以你不小心创建了一个正则表达式,它也会捕获cnnPcomcnn comcnn\com。虽然它可能满足您的需求,但最好更明确:

  sed -r '/^cnn\.com\b/d' raw.txt 

这里的区别在于. 句点之前的\ 反斜杠。这会转义句点元字符,因此将其视为文字句点。


至于以空格开头的行,您可以在单个正则表达式中捕获它们(再次转义句点元字符):

  sed -r '/(^[ ]*|^)127\.0\.0\.1\b/d' raw.txt

这个(^[ ]*|^) 表示以任意数量的重复空格开头的行^[ ]*|^ 开头,然后是127.0.0.1 的匹配项。


然后为了将它们串在一起,您可以使用括号内的| OR 运算符来捕获所有匹配项:

  sed -r '/(^[ ]*|^)(127\.0\.0\.1|cnn\.com|0\.0\.0\.0)\b/d' raw.txt

您也可以使用; 分号来分隔不同的正则表达式:

  sed -r '/(^[ ]*|^)127\.0\.0\.1\b/d; /(^[ ]*|^)cnn\.com\b/d; /(^[ ]*|^)0\.0\.0\.0\b/d;' raw.txt

【讨论】:

    【解决方案2】:

    sed 不理解字符串匹配,只理解正则表达式,并且尝试让 sed 表现得像它一样非常困难,请参阅Is it possible to escape regex metacharacters reliably with sed。要删除第一个以空格分隔的单词为“foo”的行,只需:

    awk '$1 != "foo"' file
    

    要删除以“foo”或“bar”开头的行,只需:

    awk '($1 != "foo") && ($1 != "bar")' file
    

    如果您有多个单词,那么方法是将它们全部列出并创建一个由它们索引的哈希表,然后测试您的行的第一个单词是否是哈希表的索引:

    awk 'BEGIN{split("foo bar other word",badWords)} !($1 in badWords)' file
    

    如果这不是您想要的,请编辑您的问题以阐明您的要求,并包括简洁、可测试的示例输入和 给定该输入的预期输出。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-04-05
      • 1970-01-01
      • 2015-06-04
      • 1970-01-01
      • 2014-04-20
      • 2011-09-25
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多