4

sed用来查找和替换文本,例如:

set -i 's/a/b/g' ./file.txt

a这将替换文件中的每个with实例b。我需要添加一个异常,以便替换withsed的每个实例,但文件中的第一次出现除外,例如:ab

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.

如何修改我的脚本以仅替换withsed的每个实例,除了第一次出现?ab

我有 GNU sed 4.2.1 版。

4

3 回答 3

5

您可以使用更复杂的脚本进行更完整的实现:

#!/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
于 2012-10-17T15:16:07.610 回答
5

这可能对您有用(GNU sed):

sed 's/a/b/2g' file

或者

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

这可以定制,例如

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

将开始替换abafter5 a

于 2012-10-17T14:57:49.613 回答
2

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

sed -e 'y/a/\n/' -e 's/\n/a/g' -e 'y/\n/b/'

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

上面的工作是逐行的,如果你想将它应用到整个文件,首先将整个文件变成一行:

<infile tr '\n' '^A' | sed 'y/a/\n/; s/\n/a/; y/\n/b/' | tr '^A' '\n'

或者更简单地使用potong回答中的 sed 命令:

<infile tr '\n' '^A' | sed 's/a/b/2g' | tr '^A' '\n'

注意^A(ASCII 0x01)可以用Ctrl-vCtrl-a. ^Aintr可以替换为\001.

这假定该文件不包含^A.

于 2012-10-17T14:49:48.970 回答