2012-10-17 81 views
3

我使用sed查找和替換文本,例如:如何查找和替換每場比賽除了第一個使用SED?

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

這取代的a每個實例與文件中b。我需要添加一個例外,這樣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腳本只與b取代的a每個實例,除了第一次出現?

我已經GNU的sed版本4.2.1。

回答

1

的一種方法是替換所有再反向第一替換(感謝波東):

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' 

或者更簡單地使用sed命令從波東的答案:

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

^A(ASCII 0×01)可與CTRL-v按Ctrl-a來製造。在tr^A可以通過\001代替。

這假定該文件不包含^A

+0

如果一行僅包含'baa'會怎麼樣? – potong

+0

@potong:你說的對,我錯過了。 – Thor

+1

你的方法仍然有效,但你必須首先使用一個獨特的字符,即'sed'y/a/\ n /; s/\ n/a /; y/\ n/b /'文件' – potong

5

這可能會爲你工作(GNU SED):

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

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

這可能是taylored例如

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

會開始後5a的與b更換a

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 
} 

的這個功能是很容易解釋in pseudo-code

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 
+0

** + 1 ** ...非常好地解釋。 – ghoti