我正在使用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
脚本,仅将a
的每个实例替换为b
,第一次出现除外?
我有GNU sed版本4.2.1。
答案 0 :(得分: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
在a
b
之后将开始用5
替换a
答案 1 :(得分: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
答案 2 :(得分:1)
一种方法是替换所有然后反转第一次替换(感谢 potong ):
sed -e 'y/a/\n/' -e 's/\n/a/g' -e 'y/\n/b/'
Newline用作中间名,因此以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-v Ctrl-a 生成。 ^A
中的tr
可以由\001
替换。
这假设该文件不包含^A
。