【问题标题】:Combining awk and sed to match line and replace characters结合 awk 和 sed 来匹配行和替换字符
【发布时间】:2014-01-16 08:37:02
【问题描述】:

我正在尝试匹配第一个字母,在本例中为“B”,第二列“2”。找到匹配项时,将字符 [38-41] 替换为空格。

这是我要修改的数据:

A1234A123 1 2 12345.12345 1234.1234.112341234

B1234A123 2 2 12345.12345 1234.1234.112341234

A1234A123 2 2 12345.12345 1234.1234.112341234

我可以使用 awk 匹配条件:

awk '/^B/ && $2=="2" {print}' 

我可以使用 sed 修改行:

sed -r 's/^(.{37})(.{4})/\1    /' 

我试图在文件中找到包含这两个条件的行,然后修改字符,同时仍然打印整行不匹配的行。你能结合这两个命令来引入某种 if/then 语句吗?

我尝试合并命令,但它编辑了所有行:

awk '/^B/ && $2=="2" {print}' ¦ sed -r 's/^(.{37})(.{4})/\1    /' data

结果数据应如下所示:

A1234A123 1 2 12345.12345 1234.1234.112341234

B1234A123 2 2 12345.12345 1234.1234.1    1234

A1234A123 2 2 12345.12345 1234.1234.112341234

提前致谢。

【问题讨论】:

  • 您永远不需要结合 sed 和 awk(或 grep 和 awk)。 sed 是用于在单行上进行简单替换的出色工具,对于任何其他文本操作,只需使用 awk。
  • 好的 @Ed,感谢您对其他帖子的建议和更正。我在想解决方案比它最终更难。我在 AWK 上阅读的越多,我就越意识到它的潜力。我会继续学习的!再次感谢。
  • 关于该链接的讨论都很好,但要了解这两个工具的重要一点是 sed 是在 awk 之前发明的。一旦 awk 在 1970 年代中期被发明,大多数 seds 语言结构就已经过时了,所以今天唯一有用的 sed 结构是 s、g 和 p(带有 -n 选项),并且任何时候你使用保持空间或模式空间或无论其他“空间” sed 支持什么,您都使用了错误的工具。 sed 是在单行上进行简单替换的出色工具 - 就是这样。

标签: regex sed awk


【解决方案1】:

您可以指示 sed 通过添加正则表达式来仅替换匹配的行 (/^B[^ ]* 2/):

sed -r '/^B[^\s]*\s2\s/s/^(.{37}).{4}/\1    /' data

【讨论】:

  • Whatchout 2 可以匹配 20。无需将要丢弃的部分分组。
  • @potong 你是绝对正确的。我刚刚复制了 OP 的正则表达式。
  • 复制线程中一个你知道不知道如何解决问题的人的代码总是很危险的:-)。
  • @EdMorton 在这种情况下并不危险 ;-)
【解决方案2】:

使用 GNU awk:

gawk '/^B/ && $2=="2" {print gensub(/(.{37}).{4}/,"\\1    ","")}' data

【讨论】:

    【解决方案3】:

    在 Gnu Awk 版本 4 中,您可以尝试:

    gawk 'BEGIN { FIELDWIDTHS = "1 9 1 26 4 20"; OFS="" }
    $1=="B" && $3=="2" {
        $5="    "
    } 1' file
    

    带输出:

    A1234A123 1 2 12345.12345 1234.1234.112341234
    B1234A123 2 2 12345.12345 1234.1234.1    1234
    A1234A123 2 2 12345.12345 1234.1234.112341234
    

    【讨论】:

      【解决方案4】:

      您可以使用单个 awk 来组合两个命令:

      awk '/^B/ && $2=="2"{$0=substr($0, 1, 37) "    " substr($0, 38, 4)} 1' file
      A1234A123 1 2 12345.12345 1234.1234.112341234
      B1234A123 2 2 12345.12345 1234.1234.1    1234
      A1234A123 2 2 12345.12345 1234.1234.112341234
      

      【讨论】:

      • 知道了!谢谢!实际上,我只是更改了最后一个 substr 的字符位置,以便保留最后四个字符。 awk '/^B/ && $2=="2"{$0=substr($0, 1, 37) " " substr($0, 42, 4)} 1' file
      • 不客气,是的,substr($0, 42, 4) 也会在输出中返回 1234
      • 你不需要最后一个 substr() 中的 , 4 参数。
      • 是的,如果选择正确的字符串的大部分,那么 substr 中不需要第二个参数
      猜你喜欢
      • 2016-08-27
      • 1970-01-01
      • 2015-12-18
      • 1970-01-01
      • 2013-11-14
      • 2016-10-29
      • 1970-01-01
      • 1970-01-01
      • 2013-06-01
      相关资源
      最近更新 更多