【问题标题】:Using SED to remove newlines for an address range使用 SED 删除地址范围的换行符
【发布时间】:2014-05-12 03:19:52
【问题描述】:

我在让我的 SED 脚本正常工作时遇到了一些困难。它似乎只适用于第一次出现。我基本上是一个 UNIX 初学者——请多多包涵。

数据文件如下所示:

exec cics 
end-exec.
exec cics 
send map
end-exec.
exec cics 
end-exec.

实际输出如下,似乎只有在第一次出现时才能正常工作:

exec cics end-exec.
exec cics 
send map
end-exec.
exec cics 
end-exec.

所需的输出应如下所示:

exec cics end-exec.
exec cics send map end-exec.
exec cics end-exec.

以“exec cics”开头并以“end-exec”结尾的所有内容都应位于同一行,并删除所有换行符。

SED脚本如下:

/exec cics/,/end-exec/{
:a    
N
$!ba
s/\n//
}

我从这里得到了花括号内的代码:How can I replace a newline (\n) using sed?

我的初始脚本没有:a;N;$!ba。谁能看到我遗漏了什么或做错了什么?

【问题讨论】:

  • 您应该注意,x-ref 的问题使用s/\n/ /g 而不是s/\n//

标签: regex sed


【解决方案1】:

你得到的结果可以解释为你只替换了第一个换行符:

s/\n//

但是,即使您在全局范围内执行了替换,即使用:

s/\n//g

你会得到:

exec cics end-exec. exec cics  send map end-exec. exec cics  end-exec.

因为$ 地址将匹配文件中最后出现的位置。

除非匹配最后一行,否则不要分支到标签a,当遇到end-exec 时不要分支。说:

sed '/exec cics/,/end-exec/{:a;N;/end-exec/!ba;s/\n/ /g}' filename

会产生:

exec cics end-exec.
exec cics send map end-exec.
exec cics end-exec.

如果您的输入由从exec cisc 开始并以end-exec 结尾的连续块组成,您可以简化它:

sed ':a;N;/end-exec/!ba;s/\n/ /g' filename

【讨论】:

  • 第二种方案似乎效率最高。
【解决方案2】:

如果你想试试awk

awk '{printf (/exec cics/ && NR>1?RS:"")"%s",$0} END {print ""}'
exec cics end-exec.
exec cics send mapend-exec.
exec cics end-exec.

如果行以exec cics 开头而不是第一行,则在行前添加换行符。
否则,只打印一行数据。

【讨论】:

    【解决方案3】:

    sed 脚本的这个修改版本似乎可以完成这项工作:

    /exec cics/,/end-exec/{
        :a
        /end-exec/! N
        s/\n/ /g
        t a
    }
    

    当保存在文件sed.script中,并给定数据文件(data2):

    exec cics
    end-exec.
    exec cics
    send map
    end-exec.
    exec cics
    end-exec.
    exec cics
    do this
    and that
    and tother
    end-exec.
    

    (任何数据行上都没有尾随空格),然后我得到:

    $ sed -f sed.script data2
    exec cics end-exec.
    exec cics send map end-exec.
    exec cics end-exec.
    exec cics do this and that and tother end-exec.
    $
    

    脚本的作用是什么?

    1. 对于exec cicsend-exec 之间的每个行范围,
    2. 设置标签a,
    3. 如果模式空间不包含end-exec,请在其中添加另一行。
    4. 用空格替换所有换行符。
    5. 如果有替换,请跳回标签a

    在调试/设计这个时,我在t 之后和} 之前添加了几行:

    s/^/[[/
    s/$/]]/
    

    这帮助我了解了如何使用各种其他版本的命令(包括原始命令)处理数据;这些行在打印时包含在[[]] 中。

    使用提供的 BSD sed 在 Mac OS X 10.9.2 Mavericks 上测试。

    【讨论】:

    • +1 用于解释(并使其与 BSD :) 一起使用)。不过,解决方案中的 g 标志是多余的,因为我们每次都在附加下一行后运行替换。
    • @jaypal:是的,不需要替代品上的全局后缀,尽管它不太可能造成可衡量的伤害。脚本的一个版本需要它,我想,但它是很久以前的事了,我不记得了。
    • 当然,它的存在不会造成任何伤害。我只是在想,不是在附加的每一行上都进行替换,更好、更便宜的方法是先构建我们的整个行,然后只进行一次全局替换。 devnull 提出的第二个解决方案似乎可以做到这一点,尽管它只是 GNU sed
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-21
    • 2011-08-17
    • 1970-01-01
    • 1970-01-01
    • 2015-02-15
    相关资源
    最近更新 更多