【问题标题】:Remove \n on a few lines with sed用 sed 在几行删除 \n
【发布时间】:2014-10-16 22:07:50
【问题描述】:

我正在尝试使用 sed 删除两个搜索模式之间的所有换行符。

我首先找到了this post,它教会了我如何跨行在两个模式之间进行搜索。

sed -e '/begin/,/end/{s/begin/replacement/p;d}'

然后我找到了this post 来帮助删除文件中的所有换行符。

sed ':a;N;$!ba;s/\n/ /g'

我尝试将这两个答案结合起来并得出:

sed -e '/begin/,/end/{:a;N;$!ba;s/\n/ /p;d}'

但是,它并不完全有效。它从正确的行开始替换换行符,但一直持续到文件末尾。下面给出一个例子:

Sed 命令:

sed -e '/Seven/,/Fifteen/{:a;N;$!ba;s/\n/ /g}' input.txt

输入.txt:

One Two Three
Four Five Six
Seven Eight Nine
Ten Eleven Twelve
Thirteen Fourteen Fifteen
Sixteen Seventeen Eighteen
Nineteen Twenty Twenty-One

输出:

One Two Three
Four Five Six
Seven Eight Nine Ten Eleven Twelve Thirteen Fourteen Fifteen Sixteen Seventeen Eighteen Nineteen Twenty Twenty-One

我真正想要的:

One Two Three
Four Five Six
Seven Eight Nine Ten Eleven Twelve Thirteen Fourteen Fifteen
Sixteen Seventeen Eighteen
Nineteen Twenty Twenty-One

感谢您的帮助!

【问题讨论】:

    标签: regex sed


    【解决方案1】:

    这是awk 版本:

    awk '/Seven/ && !g {f=1;g=1} /Fifteen/ {f=0} {printf "%s%s",$0,(f?FS:RS)}' file
    One Two Three
    Four Five Six
    Seven Eight Nine Ten Eleven Twelve Thirteen Fourteen Fifteen
    Sixteen Seventeen Eighteen
    Nineteen Twenty Twenty-One
    

    这是gnu awk 版本(字边界):

    awk '/\<Seven\>/ {f=1} /\<Fifteen\>/ {f=0} {printf "%s%s",$0,(f?FS:RS)}' file
    One Two Three
    Four Five Six
    Seven Eight Nine Ten Eleven Twelve Thirteen Fourteen Fifteen
    Sixteen Seventeen Eighteen
    Nineteen Twenty Twenty-One
    

    另一个awk 版本:

    awk '/Seven/ && !/Seven[[:alnum:]]/ && !/[[:alnum:]]Seven/ {f=1} /Fifteen/ {f=0} {printf "%s%s",$0,(f?FS:RS)}' file
    One Two Three
    Four Five Six
    Seven Eight Nine Ten Eleven Twelve Thirteen Fourteen Fifteen
    Sixteen Seventeen Eighteen
    Nineteen Twenty Twenty-One
    

    【讨论】:

    • +1 wrt printf "%s"(f?FS:RS),$0,虽然在这种情况下它将按预期运行,但请注意,如果 FS 或 RS 曾经包含 % 字符,它将失败。它更安全,而且恕我直言,它更清晰,因为它将分隔符移动到它打印的 $0 之后,写入printf "%s%s",$0,(f?FS:RS)。仅供参考,您可以使用/(^|[^[:alnum:]_])Seven([^[:alnum:]_]|$)/ 而不是/\&lt;Seven\&gt;/,这样您就不必写/Seven/ &amp;&amp; !/Seven[[:alnum:]]/ &amp;&amp; !/[[:alnum:]]Seven/
    • Benjamin - 上述解决方案与我发布的解决方案之间的主要区别在于,如果输入文件中存在 7 但不存在 15,它们的行为方式。我的不会做任何更改,而 Jotne 的会在 7 之后用空格替换所有换行符,直到文件末尾。显然 idk 是所需的行为,因为您没有指定。
    • @EdMorton 我同意最好使用"%s%s",$0,(f?FS:RS),但对于FSRS 包含%,您需要设置它。
    • 正确。不完全确定我理解你的观点。我只是说,如果您必须将 FS 或 RS 设置为包含 % 以匹配您的数据,那么使用该语法将会失败,因此这是不使用它的另一个原因(除了清晰度之外)。
    • 我已经尝试过这些解决方案,它们确实有效。现在我真正知道的是正则表达式,而不是 sed 或 awk。说实话,我不知道如何解释上面的任何 awk 代码。我真的很想学习这些工具,所以我很欣赏基于 awk 的答案,但我已将基于 sed 的答案标记为答案,因为这就是问题的提出方式。
    【解决方案2】:

    你也可以使用sed这个方法

    sed '/Seven/{:loop ; N ;/\nSixteen/{p;d}; s/\n/ /g; t loop}' filename
    

    【讨论】:

      【解决方案3】:

      sed 是一个出色的工具,可用于单行上的简单替换,但对于其他任何事情(即任何涉及除 s、g 和 p 和 -n 之外的语言结构的任何事情)只需使用 awk。

      将 GNU awk 用于多字符 RS、\&lt;\&gt; 字边界以及 gensub():

      $ gawk -v RS='^$' -v ORS= '{
          match($0,/\<Seven\>.*\<Fifteen\>/)
          print substr($0,1,RSTART-1) \
                gensub(/\n/," ","g",substr($0,RSTART,RLENGTH)) \
                substr($0,RSTART+RLENGTH)
      }' file
      One Two Three
      Four Five Six
      Seven Eight Nine Ten Eleven Twelve Thirteen Fourteen Fifteen
      Sixteen Seventeen Eighteen
      Nineteen Twenty Twenty-One
      

      毫不夸张——在 1970 年代中期,当 awk 被发明并且人们不再需要使用 sed 进行多行编辑时,所有那些晦涩难懂的 sed 单字符语言结构(N、b、a 等)实际上已经过时了.

      【讨论】:

        【解决方案4】:

        你需要把$改成/Fifteen/

        sed -e '/Seven/,/Fifteen/{:a;N;/Fifteen/!ba;s/\n/ /g}' input.txt
        

        • $!ba => 如果不是最后一行,则跳转到 a
        • /Fifteen/!ba => 如果不匹配/Fifteen/,则跳转到a

        您可以使命令更短:

        sed '/Seven/{:a;N;/Fifteen/!ba;s/\n/ /g}' input.txt
        

        【讨论】:

        • 由于您是在代码块中控制循环,因此您不需要初始地址中的,/Fifteen/
        • 当心/Seven/... 将在给定的示例数据中匹配两次,第一次符合预期,但也匹配Seventeen。这永远不会与以下Fifteen 匹配,因此以文件结尾和N 命令终止。因为如果要改进上述命令,这可能会产生意想不到的结果,也许/\&lt;Seven\&gt;/ 可能更安全。
        猜你喜欢
        • 2021-01-07
        • 1970-01-01
        • 2015-05-20
        • 1970-01-01
        • 2023-03-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多