unix sed替代n次出现失误?

时间:2018-04-12 16:04:17

标签: bash sed

假设我有一个包含字母Z的多个出现的字符串。 例如:aaZbbZccZ。 我希望每次打印该字符串的部分内容,直到下一次出现Z:

aaZ
aaZbbZ
aaZbbZccZ

所以我尝试使用unix sed,使用命令sed s/Z.*/Z/i,其中i是一个索引,我从1运行到字符串中的Z的数量。就我的理解而言:这应该删除在第一个Z之后出现的所有内容,但实际上这只有当我在sed s/Z.*/Z/中有i = 1时才有效,但不是因为我增加了i,例如,在sed s/Z.*/Z/2中,它只打印整个原始字符串。感觉好像有关于sed功能的遗漏,因为根据多个手册,它应该有效。

编辑:例如,在应用aaZbbZccZ时在字符串sed s/Z.*/Z/2中我希望有aaZbbZ,因为Z的第二次出现后的所有内容都会被删除。< / p>

3 个答案:

答案 0 :(得分:2)

下面的sed与你正在寻找的东西紧密相关,除了它也删除了最后的Z。

$echo aaZbbZccZdd | sed -e 's/Z[^Z]*//1g;s/$/Z/'
aaZ

$echo aaZbbZccZdd | sed -e 's/Z[^Z]*//2g;s/$/Z/'
aaZbbZ

$echo aaZbbZccZdd | sed -e 's/Z[^Z]*//3g;s/$/Z/'
aaZbbZccZ

$echo aaZbbZccZdd | sed -e 's/Z[^Z]*//4g;s/$/Z/'
aaZbbZccZddZ

编辑: 根据亚伦的建议修改。

EDIT2: 如果您不知道字符串中有多少Z,那么在命令下方使用它会更安全。否则在末尾添加额外的Z. -r - 启用正则表达式
-e - 将sed次操作分开,与;相同,但在我看来更容易阅读。

$echo aaZbbZccZddZ | sed -r -e 's/Z[^Z]*//1g' -e 's/([^Z])$/\1Z/'
aaZ

$echo aaZbbZccZddZ | sed -r -e 's/Z[^Z]*//2g' -e 's/([^Z])$/\1Z/'
aaZbbZ

$echo aaZbbZccZddZ | sed -r -e 's/Z[^Z]*//3g' -e 's/([^Z])$/\1Z/'
aaZbbZccZ

$echo aaZbbZccZddZ | sed -r -e 's/Z[^Z]*//4g' -e 's/([^Z])$/\1Z/'
aaZbbZccZddZ

$echo aaZbbZccZddZ | sed -r -e 's/Z[^Z]*//5g' -e 's/([^Z])$/\1Z/'
aaZbbZccZddZ

答案 1 :(得分:0)

除非您的字符串可以包含换行符,否则这应该符合您的预期(请参阅注释):

# -n will prevent default printing
echo 'aaZbbZccZ' | sed -n '{
    # Add a line break after each 'Z'
    s/Z/Z\
/g
    # Print it and consume it in the next sed command
    p
}' | sed -n '{
    # Add only the first line to the hold buffer (you can remove it if you don't mind to see first blank line)
    1 {
        h
    }
    # As for the rest of the lines
    2,$ {
        # Replace the hold buffer with the pattern space
        x
        # Remove line breaks
        s/\n//
        # Print the result
        p
        # Get the hold buffer again (matched line)
        x
        # And append it with new line to the hold buffer
        H
    }'

我们的想法是将字符串分解为多个行(​​每个行以Z结尾),将在第二个sed命令上逐个处理。

在第二个sed上,我们使用Hold Buffer来记住上一行,打印汇总结果,添加新行,每次删除我们之前添加的换行符。

输出

aaZ
aaZbbZ
aaZbbZccZ

答案 2 :(得分:0)

这可能适合你(GNU sed):

sed -n 's/Z/&\n/g;:a;/\n/P;s/\n\(.*Z\)/\1/;ta' file

使用sed的类似grep的选项-n来明确打印内容。在每个Z之后附加换行符。如果没有替代品那么就没有什么可做的。打印到第一个换行符,如果以下字符包含Z,则删除第一个换行符并重复。