【问题标题】:SED script not matching single in Multiline pattern after line breaks换行后 SED 脚本与多行模式中的单个不匹配
【发布时间】:2015-04-29 14:14:36
【问题描述】:

我正在尝试生成一个可以转换的 sed 脚本

&&a_x* &&b_x;cx &&d_x*

进入

a_x
ax
b_x 
cx 
d_x
dx

* 应该触发复制,删除 _; 是一个简单的换行符。

我有一个 SED 脚本,它首先插入换行符(包括带有 ; 的操作),然后在没有 _ 的情况下执行复制的多行模式。

如果我将多行模式移动到单独的脚本文件中并通过管道输出用于执行换行符的指令,则多行模式有效。

由于某些奇怪的原因,单个脚本文件无法执行 - 这是出于维护原因我想要的。

这是组合版本:

#!/bin/sed -f
# Remove whitespaces 
s/\ //g 
# Linebreak on &&
s/\&\&/\
\&\&/g
### Linebreak on ; 
s/\;/\
/g
# Remove extra new line
s/\n// 
:extendvars
/^..*\*$/ {
    l                         //DEBUG SWITCH
    h 
    s/\(\&\|\*\)\(\&\|\*\)*//g
    p
    g
    s/\(\&\|_\|-\|\*\)\(\&\|_\|-\|\*\)*//g
    p
    d
    bextendvars;
}

多行模式第一行中的调试开关“l”应该只匹配以 * 结尾的行,但匹配所有行和输出

&&a_x*\n&&b_x\bx\n&&c_x*$

在错误的组合版本中。管道时,sed 正确识别模式:

&&a_x*$ ... &&c_x*$

错误输出(组合版):

&&a_x*\n&&b_x\nbx\n&&c_x*$ 
a_x 
b_x 
bx 
c_x
ax 
bx 
bx 
cx

正确的输出(管道版本):

&&a_x*$
a_x 
ax 
&&b_x 
bx 
&&c_x*$
c_x
cx

我运行脚本

sed -f [SCRIPTNAME] <old >new

在这个版本中,我从 &amp;&amp;b_x jet 中删除了 &amp;&amp;

即使在一个脚本中执行所有语句,如何让 SED 识别正确的模式? 为什么 SED 突然无法匹配以 * 结尾的单行?

感谢您的帮助!

【问题讨论】:

    标签: regex bash sed


    【解决方案1】:

    您的代码不再循环的原因实际上与循环条件无关;就是在循环中,你运行

        d
    

    ...中止当前输入行的处理。您从输入行在模式空间中构造了几行并不重要; d 告诉 sed 停止它正在做的事情,读取下一行输入(如果有的话)并从头开始。

    无论如何,你的方法对我来说似乎过于复杂。我建议(用 GNU 的说法,因为这种机制在 GNU sed 代码中更为明显)

    #!/bin/sed -rf
    
    s/\s*(^|&&|;)\s*/\n/g      # split tokens onto several lines, make sure
                               # there's a newline in front of each (so the next
                               # regex matches all)
    s/(\n[^\n])_x\*/\1_x\1x/g  # Match lines that end with _x*, expand to
                               # \nfoo_x\nfoox
    s/^\n*//                   # remove leading newlines (we put at least one
                               # there in the beginning)
    

    您似乎煞费苦心地让代码与非 GNU sed 一起工作,所以这里有一个 POSIX 版本可以做同样的事情:

    #!/bin/sed -f
    
    s/[[:space:]]*&&[[:space:]]*/\
    /g
    s/[[:space:]]*;[[:space:]]*/\
    /g
    s/^/\
    /
    s/\(\n[^\n]\)_x\*/\1_x\1x/g
    s/^\
    *//
    

    这会删除标记周围的空格。这似乎是一件明智的事情。如果您不希望发生这种情况,则必须从代码中删除与空格匹配的部分,并且必须在标记行的末尾为空格做出规定。

    #!/bin/sed -rf
    
    s/^|&&|;/\n/g
    s/(\n[^\n])_x\*([[:blank:]]*)/\1_x\1x\2/g
    s/^\n//
    

    可能是对 GNU sed 代码的改编。

    【讨论】:

      【解决方案2】:

      在这里,一个简单的 awk 可能比 sed 更具可读性。试试这个awk 命令:

      s='&&a_x* &&b_x;cx &&d_x*'
      
      echo "$s" | awk -F '\\*' -v RS='&&|;' 'NF{s=$1;print s} NF==2{sub(/_/, "", s);print s}'
      a_x
      ax
      b_x
      cx
      d_x
      dx
      

      【讨论】:

      • 哦,我喜欢这样。闪亮的。值得注意的是,并非所有 awks 都支持正则表达式(甚至是多字符)RS,因此考虑到 OP 努力避免 sed 代码中的 GNUisms,我不确定这是否适合他,但这是一个不错的方法对大多数人来说都是这样的。
      • 是的,我应该提到它是 gnu awk
      • 是的,确实很闪亮,很酷的替代解决方案 - 我会将 AWK 放在我的列表中!
      猜你喜欢
      • 1970-01-01
      • 2021-04-02
      • 1970-01-01
      • 2015-04-10
      • 2020-01-14
      • 2021-05-23
      • 2018-01-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多