【问题标题】:Find and replace and move a line that contains a specific string查找、替换和移动包含特定字符串的行
【发布时间】:2022-11-10 22:20:11
【问题描述】:

假设我有以下文本文件:

a b c d 1 2 3
e f g h 1 2 3
i j k l 1 2 3
m n o p 1 2 3

如何在包含字母 (e) 的行中将 '1 2 3' 替换为 '4 5 6'将它移到包含字母 (k) 的行之后?

我的方法是

  1. 删除我要替换的行
  2. 找线我想移动它的那条线
  3. 找线我想移动它的那条线
  4. 将输出附加到文件中
    grep -v 'e' $original > $file
    grep -B999 'k' $file > $output
    grep 'e' $original | sed 's/1 2 3/4 5 6/' >> $output
    grep -A999 'k' $file | tail -n+2 >> $output
    rm $file
    mv $output $original
    

    但是这个解决方案有很多问题:

    1. 很多grep 似乎不必要的命令
    2. 参数-A999-B999 假设文件不会包含超过999 行,最好有另一种方法来获取匹配行之前和之后的行

      我正在寻找一种更有效的方法来实现这一目标

【问题讨论】:

  • 这是一次性替换还是全球性的?即,每行e 移动到每行k 之后?或者只是一个替换然后退出?如果每一行,什么顺序?如果找不到k 行怎么办?
  • @dawg 它应该是一个单独的替换,并且假设 k 存在

标签: awk sed grep


【解决方案1】:

这个awk 应该适合你:

awk '
/(^| )e( |$)/ {
   sub(/1 2 3/, "4 5 6")
   p = $0
   next
}
1
/(^| )k( |$)/ {
   print p
   p = ""
}' file

a b c d 1 2 3
i j k l 1 2 3
e f g h 4 5 6
m n o p 1 2 3

【讨论】:

    【解决方案2】:

    使用sed

    $ sed '/e/{s/1 2 3/4 5 6/;h;d};/k/{G}' input_file
    a b c d 1 2 3
    i j k l 1 2 3
    e f g h 4 5 6
    m n o p 1 2 3
    

    【讨论】:

    • GNU sed 只是...
    • @dawg 如果 (k) 在 (e) 之前的一行中,这将不起作用
    • @阿尔萨拉哈:如果 (k) 在 (e) 之前的一行中,这不起作用您没有将其作为要求声明,但通过两次通过即可轻松解决。
    • @dawg我没有指定它是在之后,你能说明如何做2遍吗?
    • @Alsaraha:看看编辑后的答案......
    【解决方案3】:

    这是一个 GNU awk 解决方案:

    awk '
    /<e>/{
        s=$0
        sub("1 2 3", "4 5 6", s)
        next
    }
    /<k>/ && s {
        printf("%s
    %s
    ",$0,s)
        next
    } 1
    ' file
    

    或 POSIX awk:

    awk '
    function has(x) {
        for(i=1; i<=NF; i++) if ($i==x) return 1
        return 0
    }
    
    has("e") {
        s=$0
        sub("1 2 3", "4 5 6", s)
        next
    }
    has("k") && s {
        printf("%s
    %s
    ",$0,s)
        next
    } 1
    ' file
    

    要么打印:

    a b c d 1 2 3
    i j k l 1 2 3
    e f g h 4 5 6
    m n o p 1 2 3
    

    无论文件中ek 的顺序如何,这都有效:

    awk '
    function has(x) {
        for(i=1; i<=NF; i++) if ($i==x) return 1
        return 0
    }
    
    has("e") {
        s=$0
        sub("1 2 3", "4 5 6", s)
        next
    }
    
    FNR<NR && has("k") && s {
        printf("%s
    %s
    ",$0,s)
        next
    }
    
    FNR<NR
    
    ' file file
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-19
      • 2020-03-25
      • 1970-01-01
      • 1970-01-01
      • 2017-06-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多