【问题标题】:Insert multiple lines into a file after specified pattern using shell script使用shell脚本在指定模式后将多行插入文件
【发布时间】:2014-04-25 04:32:42
【问题描述】:

我想使用 shell 脚本在一个文件中插入多行。 让我们考虑一下我的输入文件内容是: input.txt:

abcd
accd
cdef
line
web

现在我必须在 input.txt 文件中的“cdef”行之后插入四行。 插入我的文件后应该是这样的:

abcd
accd
cdef
line1
line2
line3
line4
line
web

我应该使用 shell 脚本进行上述插入。谁能帮帮我?

【问题讨论】:

    标签: linux bash shell sed awk


    【解决方案1】:

    另一个sed

    sed '/cdef/r add.txt' input.txt
    

    输入.txt:

    abcd
    accd
    cdef
    line
    web
    

    添加.txt:

    line1
    line2
    line3
    line4
    

    测试:

    sat:~# sed '/cdef/r add.txt' input.txt
    abcd
    accd
    cdef
    line1
    line2
    line3
    line4
    line
    web
    

    如果您想应用 input.txt 文件中的更改。然后,使用-ised

    sed -i '/cdef/r add.txt' input.txt
    

    如果您想使用正则表达式作为表达式,您必须使用带有sed-E 标签。

    sed -E '/RegexPattern/r add.txt' input.txt
    

    【讨论】:

    • 有没有办法反其道而行之(从 input.txt 中删除 add.txt 中的文本)?
    • 允许匿名文件的一种变体是将此处的文档通过管道传输到 sed 调用中,并使用r 命令从/dev/stdin 中读取。
    • 嗨,有没有一种快速的方法可以在 add.txt 的添加行之前添加 4 个空格?
    【解决方案2】:

    使用 GNU sed:

    sed "/cdef/aline1\nline2\nline3\nline4" input.txt
    

    如果您开始:

    abcd
    accd
    cdef
    line
    web
    

    这会产生:

    abcd
    accd
    cdef
    line1
    line2
    line3
    line4
    line
    web
    

    如果您想就地保存对文件的更改,请说:

    sed -i "/cdef/aline1\nline2\nline3\nline4" input.txt
    

    【讨论】:

    • 我是sed 的新手,但哇,我爱上了它的强大功能!如果你想追加一个空的换行符first,你必须像这样在追加命令之后转义反斜杠字符:sed "/cdef/a\\\nline1\nline2\nline3\nline4" input.txt。我不确定它为什么会这样,如果有人能解释一下就好了!
    • 当前命令在每次提到cdef 时插入行*,有没有办法让它只在第一次遇到cdef 时插入,不再插入?跨度>
    • MacOS sed 没有实现与 GNU sed 完全相同的 a 命令,因此上述方法在没有 mods 的 MacOS 中不起作用 - 至少从 macOS 10.13 开始(请参阅unix.stackexchange.com/a/131940/230763)
    【解决方案3】:
    sed '/^cdef$/r'<(
        echo "line1"
        echo "line2"
        echo "line3"
        echo "line4"
    ) -i -- input.txt
    

    【讨论】:

    • 错过了这个好答案。 sed '/^cdef$/r' &lt;(printf "%s\n" line{1..4}) -i -- input.txt 更短但可读性更差。
    • 请注意,当您从主机发出命令时,这在容器中不起作用,因为来自&lt;(...) 的文件描述符将在主机而不是客户机上创建。使用/someline/a&lt;added\ncontent&gt; 方法效果更好,特别是如果您执行sed "/someline/a$(echo 'here you can have newlines' | tr \\n @ | sed '\''s/@/\\n/g'\')" -i -- input.txt 之类的操作(不是完整示例且未经过适当测试,我现在没有时间,但这应该包括您需要的构建块) .
    【解决方案4】:

    使用awk

    awk '/cdef/{print $0 RS "line1" RS "line2" RS "line3" RS "line4";next}1' input.txt 
    

    说明:

    • 您使用/.../ 找到要插入的行
    • 您使用print $0 打印当前行
    • RS 是内置的awk 变量,默认设置为new-line
    • 您添加由该变量分隔的新行
    • 1 最后导致每隔一行打印。在它之前使用next 可以让我们阻止当前行,因为您已经使用print $0 打印了它。

    $ awk '/cdef/{print $0 RS "line1" RS "line2" RS "line3" RS "line4";next}1' input.txt
    abcd
    accd
    cdef
    line1
    line2
    line3
    line4
    line
    web
    

    要更改文件,您可以:

    awk '...' input.txt > tmp && mv tmp input.txt
    

    【讨论】:

      【解决方案5】:

      这是一个基于@rindeal solution 的更通用的解决方案,它不适用于 MacOS/BSD(/r 需要一个文件):

      cat << DOC > input.txt
      abc
      cdef
      line
      DOC
      
      $ cat << EOF | sed '/^cdef$/ r /dev/stdin' input.txt
      line 1
      line 2
      EOF
      
      # outputs:
      abc
      cdef
      line 1
      line 2
      line
      

      这可用于将任何内容通过管道传输到给定位置的文件中:

      $ date | sed '/^cdef$/ r /dev/stdin' input.txt
      
      # outputs
      abc
      cdef
      Tue Mar 17 10:50:15 CET 2020
      line
      

      另外,您可以添加多个命令来删除标记行cdef

      $ date | sed '/^cdef$/ {
        r /dev/stdin
        d
      }' input.txt
      
      # outputs
      abc
      Tue Mar 17 10:53:53 CET 2020
      line
      

      【讨论】:

        【解决方案6】:

        这个答案很容易理解

        • 在模式前复制
        • 添加你的台词
        • 在模式之后复制
        • 替换原文件

          FILENAME='app/Providers/AuthServiceProvider.php'

        STEP 1 复制直到图案

        sed '/THEPATTERNYOUARELOOKINGFOR/Q' $FILENAME >>${FILENAME}_temp
        

        第 2 步添加您的行

        cat << 'EOL' >> ${FILENAME}_temp
        
        HERE YOU COPY AND
        PASTE MULTIPLE
        LINES, ALSO YOU CAN
        //WRITE COMMENTS
        
        AND NEW LINES
        AND SPECIAL CHARS LIKE $THISONE
        
        EOL
        

        第 3 步添加文件的其余部分

        grep -A 9999 'THEPATTERNYOUARELOOKINGFOR' $FILENAME >>${FILENAME}_temp
        

        替换原文件

        mv ${FILENAME}_temp $FILENAME
        

        如果您需要变量,请在第 2 步中将“EOL”替换为 EOL

        cat << EOL >> ${FILENAME}_temp
        
        this variable will expand: $variable1
        
        EOL
        

        【讨论】:

        • 没必要尖叫

        【解决方案7】:

        我需要用最少的工具来模板化一些文件,对我来说,上面 sed -e '/../r file.txt 的问题是它只在打印出匹配的其余部分后附加文件,而不是替换它。

        这不行(所有匹配都被替换,模式匹配从同一点继续)

        #!/bin/bash
        
        TEMPDIR=$(mktemp -d "${TMPDIR:-/tmp/}$(basename $0).XXXXXXXXXXXX")
        # remove on exit
        trap "rm -rf $TEMPDIR" EXIT
        
        DCTEMPLATE=$TEMPDIR/dctemplate.txt
        DCTEMPFILE=$TEMPDIR/dctempfile.txt
        
        # template that will replace
        printf "0replacement
        1${SHELL} data
        2anotherlinenoEOL" > $DCTEMPLATE
        
        # test data
        echo -e "xxy \n987 \nxx xx\n yz yxxyy" > $DCTEMPFILE
        
        # print original for debug
        echo "---8<--- $DCTEMPFILE"
        cat $DCTEMPFILE
        echo "---8<--- $DCTEMPLATE"
        cat $DCTEMPLATE
        echo "---8<---"
        
        # replace 'xx' -> contents of $DCTEMPFILE
        perl -e "our \$fname = '${DCTEMPLATE}';" -pe 's/xx/`cat $fname`/eg' ${DCTEMPFILE}
        

        【讨论】:

          【解决方案8】:

          您可以使用awkinput.txt 中间插入某些命令的输出。
          要插入的行可以是cat otherfilels -l 的输出或带有printf 生成的数字的4 行。

          awk 'NR==FNR {a[NR]=$0;next}
              {print}
              /cdef/ {for (i=1; i <= length(a); i++) { print a[i] }}'
              <(printf "%s\n" line{1..4}) input.txt
          

          【讨论】:

            【解决方案9】:

            如果您想使用 bash 脚本来执行此操作,这很有用。

            echo $password | echo 'net.ipv4.ping_group_range=0 2147483647' |  sudo -S tee -a /etc/sysctl.conf
            

            【讨论】:

            • 您能否为您的命令添加一些解释,以帮助未来的读者了解所做的工作?
            【解决方案10】:

            假设您有一个名为“insert.txt”的文件,其中包含您要添加的行:

            line1
            line2
            line3
            line4
            

            如果 PATTERN 'cdef' 在您的 input.txt 文件中重复多次,并且您想在所有出现的模式 'cdef' 之后添加来自 'insert.txt' 的行,那么一个简单的解决方案是:

            sed -i -e '/cdef/r insert.txt' input.txt

            但是,如果 PATTERN 'cdef' 在您的 input.txt 文件中重复多次,并且您只想在模式第一次出现后添加来自 'insert.txt' 的行,那么一个漂亮的解决方案是:

            printf "%s\n" "/cdef/r insert.txt" w | ed -s input.txt

            如果模式在您的 input.txt 文件中只出现一次,这两种解决方案都可以正常工作。

            【讨论】:

              猜你喜欢
              • 2021-10-12
              • 2018-12-18
              • 1970-01-01
              • 2019-10-22
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-08-15
              • 2018-11-18
              相关资源
              最近更新 更多