【问题标题】:Insert new line after last occurence of string in bash在 bash 中最后一次出现字符串后插入新行
【发布时间】:2014-08-29 11:27:19
【问题描述】:

我正在尝试在 bash 中最后一次出现字符串之后添加新行。

例如,如果我有以下文本:

GG1 test-35
GG1 test-38
GG1 test-40

HH1 test-52
HH1 test-60
HH1 test-32
HH1 test-40

LL1 test-101
LL1 test-99
LL1 test-24

假设我想在“HH”块的末尾添加一个新行,所以它会变成:

HH1 test-52
HH1 test-60
HH1 test-32
HH1 test-40
HH1 test-56

到目前为止,我已尝试使用 sed 和 awk,但似乎无法正确使用。如果我可以搜索一个实际的测试编号,例如 HH1 test-40,这很简单,但我唯一可以搜索的是首字母缩略词。所以我需要 HH1 的最后一行出现,然后在它之后添加一个新行。

感谢任何帮助。

【问题讨论】:

  • 您想只打印 HH1 块还是整个文件?
  • 整个文件,它只是包含新的 HH1 test-56 行
  • 输入是什么? test-56 添加到区块 XX 或直接HH1 test-56 添加到区块(或创建新区块)

标签: bash awk sed newline


【解决方案1】:

gawk 又快又脏:

 awk 'BEGIN{RS="";ORS="\n\n"}/^HH/{$0=$0"\nHH1 test-56"}7' file

它很脏,因为它在输出末尾留下了一个空行。

【讨论】:

  • 如果最后一个HH1后面没有空行就不行了。
  • @AvinashRaj OP 说HH block。我的解决方案来自我对问题和 OP 示例的理解。
  • 我认为他的意思是 HH 块仅用于示例。请参阅第一行“我正在尝试在 bash 中最后一次出现字符串之后添加新行。”
  • @AvinashRaj I wanted to add a new line at the end of the 'HH' block, 也是 OP 的 "answer(deleted)":that worked like a charm! 。无论如何,如果 OP 数据像你假设的那样,你是对的,我的单行将行不通。处理文件两次(或将文件保存在内存中)将修复它。很容易做到。
  • 感谢大家的所有回答!是的,很抱歉没有更清楚,肯特的解决方案正在按我的意愿工作!我想知道您是否可以帮助我解决另一个问题。我想传入shell变量来替换上例中的“HH”和“HH1 test 56”,而且运气不好!
【解决方案2】:

有很多选择:

awk '/HH/{seen++} seen && !/HH/{print "HH1 test-56"; seen=0} 1' file

或:

tac file | awk '/HH/ && !seen{print "HH1 test-56"; seen++} 1' | tac

或:

awk 'NR==FNR{if (/HH/) nr=NR; next} 1; FNR==nr{print "HH1 test-56"}' file file

或者(gawk-only for multi-char RS):

gawk -v RS='^$' -v ORS= '{sub(/.*HH[^\n]+\n/,"&HH1 test-56\n")} 1' file

或者....

【讨论】:

    【解决方案3】:

    再来一个 awk 应该在所有 awks 中工作

    awk 'a=/^HH/{b=1}b&&!a{print "HH1 test-56";b=0}1' file
    

    awk -F- 'a=/HH/{b=$1}b&&!a{print b"-56";b=0}1' file
    

    【讨论】:

      【解决方案4】:

      这可能对你有用(GNU sed 和 Bash):

      sed '/^HH1/!b;:a;n;//ba;i\HH1 test-56' file
      

      如果该行不以HH1 开头,则正常打印,否则打印直到该行不以HH1 开头,然后插入换行符。

      【讨论】:

        【解决方案5】:
        LineToAdd="HH1 test-56"
        { echo "${LineToAdd}"; cat YourFile; } | sed -n '1x;H;${x
           s/^\([^ ]\{3\}\) \([^[:cntrl:]]*\)\(\n\)\(.*\)\1 \([^[:cntrl:]]*\)\3/\4\1 \5\3\1 \2\3/
           s/^\n//
           p
           }'
        

        解释

        • 在内容开头添加要添加的行(可以通过在结尾添加一些代码来添加)
        • 加载缓冲区中的所有行
        • 在具有第 1 组的最新行之后移动(通过重写组位置替换)第 2 组第一行(因此第 1 组作为 HH1 和 test-56 作为第 2 组)。(假设没有 HH1,这里是快速和肮脏的在以下一行内容中)
        • 如果有新行则删除第一行(快速和肮脏,假设原始文件不以新行开头)
        • 打印结果 -

        【讨论】:

          【解决方案6】:

          下面的 perl 命令会在最后一行 HH1 之后添加一个新行,

          perl -0777pe 's/(?s)(?<=HH1\stest-)(\d+\n)(?=(?:(?!HH1\stest-).)*$)/\1HH1 test-56\n/' file
          

          示例:

          $ cat file
          HH1 test-52
          HH1 test-60
          HH1 test-32
          
          LL1 test-101
          LL1 test-99
          HH1 test-40
          LL1 test-24
          

          $ perl -0777pe 's/(?s)(?<=HH1\stest-)(\d+\n)(?=(?:(?!HH1\stest-).)*$)/\1HH1 test-56\n/' file
          HH1 test-52
          HH1 test-60
          HH1 test-32
          
          LL1 test-101
          LL1 test-99
          HH1 test-40
          HH1 test-56
          LL1 test-24
          

          【讨论】:

            【解决方案7】:

            一个小的 bash 脚本也可以提供您正在寻找的灵活性和字符串添加:

            #!/bin/bash
            
            ## Usage:
            #
            # ./scriptname datafile [new-sting-to-add (HH1 test-56)] [string-to-search (HH1)]
            
            newstr="${2:-HH1 test-56}"          # set newstr
            srchstr="${3:-"${newstr// */}"}"    # set srchstr
            found=1                             # set found flag to false
            
            # read datafile line-by-line
            while read pfx tststr || [ -n "$tststr" ] ; do
                [ "$pfx" == "$srchstr" ] && found=0                 # if pfx matches set flag
                [ $found -eq 0 ] && [ "$pfx" != "$srchstr" ] && {   # if flag and no match
                    echo "$newstr"                                  # add newstr to output
                    found=1                                         # reset flag to false
                }
                echo "$pfx $tststr"             # normal output
            
            done <"$1"
            

            输出:

            $ ./hh.sh dat/hh.dat    # (using default values)
            GG1 test-35
            GG1 test-38
            GG1 test-40
            
            HH1 test-52
            HH1 test-60
            HH1 test-32
            HH1 test-40
            HH1 test-56
            
            LL1 test-101
            LL1 test-99
            LL1 test-24
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2015-05-11
              • 2012-06-05
              • 2012-03-17
              • 2012-05-31
              • 2021-08-22
              • 2023-02-04
              • 1970-01-01
              • 2011-04-19
              相关资源
              最近更新 更多