首页 > 解决方案 > sed -f 没有针对多行的输入文件运行多个类似的模式匹配命令,包括连接?

问题描述

我在使用 -f 运行的批处理文件中有一堆 sed 命令。

/PATTERN1 /I,/;/s/^[ \t]*//g
/PATTERN1 /I{:a;/;/!N;s/\n/ /;ta;P;D}
s/\(PATTERN1\) \([ \tA-Za-z0-9,\"\']*\)(\(.*\))[ \t]*;[ \t]*$/\1 \2\3;/I

如果我跑

gsed -f sed-file.sed input-file 

似乎由于有多行具有相同的模式匹配,它运行第一行并忽略其他行。如果我将这些行逐一注释掉,它们会在文件中自行正常工作,但如果我不加注释地运行它们,它只会处理第一个匹配项。

我的示例输入文件文件是

    not (this line);
pattern1 some text, ( some other text (5), some other text (6));
pattern1 this text
(
     that text (6),
     that text (7),
);
not this text either;

我希望它看起来像这样

    not (this line);
pattern1 some text,  some other text (5), some other text (6);
pattern1 this text that text (6), that text (7), ;
not this text either;

因此,如果我不注释 sed 文件中的所有行(如上所述),那么我会得到:

    not (this line);
pattern1 some text, ( some other text (5), some other text (6));
pattern1 this text (      that text (6),      that text (7), );
not this text either;

如果我注释掉前两行,我会得到

    not (this line);
pattern1 some text,  some other text (5), some other text (6);
pattern1 this text
(
     that text (6),
     that text (7),
);
not this text either;

其中带有 pattern1 的第一行正确删除了周围的括号。

如果我注释掉我得到的第一行

    not (this line);
pattern1 some text, ( some other text (5), some other text (6));
pattern1 this text (      that text (6),      that text (7), );
not this text either;

其中匹配 pattern1 的行被连接到一个包括分号的位置,但不再删除周围的括号。

如果我注释掉最后一行,我会得到 samne 但空格不会被删除......

    not (this line);
pattern1 some text, ( some other text (5), some other text (6));
pattern1 this text (      that text (6),      that text (7), );
not this text either;

如果我注释掉最后两行,我会得到:

    not (this line);
pattern1 some text, ( some other text (5), some other text (6));
pattern1 this text
(
that text (6),
that text (7),
);
not this text either;

在以 pattern1 开头并以分号结尾的行上正确删除空格的位置。

如何确保按顺序处理所有 3 个 sed,但使用一个命令?还是我必须单独运行它们?

标签: sedksh

解决方案


当您使用地址范围规范,然后在下面输入手动循环时,/PATTERN1 /I{它与地址范围冲突。

前任。例如:

seq 5 | sed -n '/1/,/3/{s/^/A/;p}; /1/{n;:a;/3/!{N;ba};p;}'

每个地址范围都会“记住”它是否输入,并且无论如何都会执行下一个命令。如果您阅读直到;手动使用Nn在手动循环中,则地址范围将等待下一个;出现停止输入。

如果在PATTERN1;自己之间进行循环,无论如何都只需自己删除^[ \t]*换行符之后。

最多删除模式空间中的D第一个换行符,因此在删除所有换行符后s/\n/ /,它将有效地删除所有内容。

我想你会想要:

# if pattern is found
/PATTERN1 /I{
     # remove leading whitespaces 
     # I prefer [[:space:]]*
     s/^[ \t]*//
     # buffer everything until ';' is found
     :a; /;/!{N;ba;};
     # remove leading whitespaces after a newline
     s/\n[ \t]*/ /g; 
}
# remove the ( ... )
s/\(PATTERN1\) \([ \tA-Za-z0-9,\"\']*\)(\(.*\))[ \t]*;[ \t]*$/\1 \2\3;/I

输出

    not (this line);
pattern1 some text,  some other text (5), some other text (6);
pattern1 this text  that text (6), that text (7), ;
not this text either;

输出:


推荐阅读