SED 脚本在换行后不匹配多行模式中的单个

SED script not matching single in Multiline pattern after line breaks

我正在尝试生成一个 sed 脚本来转换

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

进入

a_x
ax
b_x 
cx 
d_x
dx

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

我有一个 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

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

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

感谢您的帮助!

您的代码不再循环的原因实际上与循环条件没有任何关系;就是在循环内部,你 运行

    d

...中止当前输入行的处理。您从输入行在模式 space 中构造了几行是没有意义的; 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\*/_xx/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\*/_xx/g
s/^\
*//

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

#!/bin/sed -rf

s/^|&&|;/\n/g
s/(\n[^\n])_x\*([[:blank:]]*)/_xx/g
s/^\n//

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

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

s='&&a_x* &&b_x;cx &&d_x*'

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