如何使用sed查找和替换除第一个匹配项之外的所有匹配项?

如何使用sed查找和替换除第一个匹配项之外的所有匹配项?,sed,Sed,我正在使用sed查找和替换文本,例如: set -i 's/a/b/g' ./file.txt 这将用文件中的b替换a的每个实例。我需要添加一个异常,sed将a的每个实例替换为b,但文件中的第一个实例除外,例如: There lived a bird who liked to eat fish. One day he fly to a tree. 这就变成了: There lived a bird who liked to ebt fish. One dby he fly to b tree

我正在使用
sed
查找和替换文本,例如:

set -i 's/a/b/g' ./file.txt
这将用文件中的
b
替换
a
的每个实例。我需要添加一个异常,
sed
a
的每个实例替换为
b
,但文件中的第一个实例除外,例如:

There lived a bird who liked to eat fish.
One day he fly to a tree.
这就变成了:

There lived a bird who liked to ebt fish.
One dby he fly to b tree.
如何修改我的
sed
脚本,使其仅将
a
的每个实例替换为
b
,第一个实例除外


我有GNU-sed版本4.2.1。

一种方法是全部替换,然后反转第一次替换(感谢Poton):

换行符用作中间字符,因此以
b
开头的字符串可以正常工作

上述方法按行操作,如果要将其应用于整个文件,请首先将整个文件分成一行:

<infile tr '\n' '^A' | sed 'y/a/\n/; s/\n/a/; y/\n/b/' | tr '^A' '\n'
这可能适合您(GNU-sed):

这可以是泰勒色的

sed ':a;s/\(\(a[^a]*\)\{5\}\)a/\1b/;ta' file

将在
5
a

之后开始用
b
替换
a
您可以使用更复杂的脚本执行更完整的实现:

#!/bin/sed -nf

/a/ {
    /a.*a/ {
        h
        s/a.*/a/
        x
        s/a/\n/
        s/^[^\n]*\n//
        s/a/b/g
        H
        g
        s/\n//
    }

    : loop
    p
    n
    s/a/b/g
    $! b loop
}
它的功能很容易用伪代码解释

if line contains "a"
    if line contains two "a"s
        tmp = line
        remove everything after the first a in line
        swap tmp and line
        replace the first a with "\n"
        remove everything up to "\n"
        replace all "a"s with "b"s
        tmp = tmp + "\n" + line
        line = tmp
        remove first "\n" from line
    end-if

    loop
        print line
        read next line
        replace all "a"s with "b"s
        repeat loop if we haven't read the last line yet
    end-loop
end-if

如果一行只包含
baa
,该怎么办?您的方法仍然有效,但必须首先使用唯一字符,即
sed'y/a/\n/;s/\n/a/;y/\n/b/'文件
我明白你的意思,使用换行符作为中介很好。+1…解释得很好。
sed ':a;s/\(a[^a]*\)a/\1b/;ta' file
sed ':a;s/\(\(a[^a]*\)\{5\}\)a/\1b/;ta' file
#!/bin/sed -nf

/a/ {
    /a.*a/ {
        h
        s/a.*/a/
        x
        s/a/\n/
        s/^[^\n]*\n//
        s/a/b/g
        H
        g
        s/\n//
    }

    : loop
    p
    n
    s/a/b/g
    $! b loop
}
if line contains "a"
    if line contains two "a"s
        tmp = line
        remove everything after the first a in line
        swap tmp and line
        replace the first a with "\n"
        remove everything up to "\n"
        replace all "a"s with "b"s
        tmp = tmp + "\n" + line
        line = tmp
        remove first "\n" from line
    end-if

    loop
        print line
        read next line
        replace all "a"s with "b"s
        repeat loop if we haven't read the last line yet
    end-loop
end-if