如何用sed一次replace多个模式?
假设我有'abbc'string,我想replace:
- ab – > bc
- bc – > ab
如果我尝试两次replace结果是不是我想要的:
echo 'abbc' | sed 's/ab/bc/g;s/bc/ab/g' abab
那么我可以使用什么种子命令来replace如下?
echo abbc | sed SED_COMMAND bcab
编辑 :其实文本可能有超过2个模式,我不知道我需要多lessreplace。 由于有一个答案,说sed
是一个stream编辑器,它的replace是贪婪的,我认为我将需要使用一些脚本语言。
也许这样的事情:
sed 's/ab/~~/g; s/bc/ab/g; s/~~/bc/g'
将~
replace为你知道不会在string中的字符。
这可能适用于你(GNU sed):
sed -r '1{x;s/^/:abbc:bcab/;x};G;s/^/\n/;:a;/\n\n/{P;d};s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/;ta;s/\n(.)/\1\n/;ta' file
这使用一个查找表,准备和保存在保持空间(HS),然后附加到每一行。 一个独特的标记(在这种情况下\n
)被预置在该行的开头,并被用作在整个行的长度上search的方法。 一旦标记到达行末,过程结束,打印出来的查找表和标记被丢弃。
注意查找表是在开始时准备好的,并且select了第二个唯一的标记(在这种情况下),以免与replacestring冲突。
有一些意见:
sed -r ' # initialize hold with :abbc:bcab 1 { x s/^/:abbc:bcab/ x } G # append hold to patt (after a \n) s/^/\n/ # prepend a \n :a /\n\n/ { P # print patt up to first \n d # delete patt & start next cycle } s/\n(ab|bc)(.*\n.*:(\1)([^:]*))/\4\n\2/ ta # goto a if sub occurred s/\n(.)/\1\n/ # move one char past the first \n ta # goto a if sub occurred '
表格是这样工作的:
** ** replacement :abbc:bcab ** ** pattern
以下是对ooga答案的一个变体,它可以用于多个search和replace对,而不必检查值可能被重用的方式:
sed -i ' s/\bAB\b/________BC________/g s/\bBC\b/________CD________/g s/________//g ' path_to_your_files/*.txt
这里是一个例子:
之前:
some text AB some more text "BC" and more text.
后:
some text BC some more text "CD" and more text.
请注意, \b
表示单词边界,这是防止________
干扰search(我在Ubuntu上使用GNU sed 4.2.2)。 如果你不使用单词边界search,那么这种技术可能无法正常工作。
另外请注意,这与删除s/________//g
并追加&& sed -i 's/________//g' path_to_your_files/*.txt
到命令末尾的结果相同,但不需要指定path两次。
如果你知道你的文件中没有出现空值,就可以使用\x0
或_\x0_
来代替________
, 正如jthill所build议的那样 。
sed
是一个stream编辑器。 它贪婪地search和replace。 做你所要求的唯一方法是使用一个中间替代模式,并最终改变它。
echo 'abcd' | sed -e 's/ab/xy/;s/cd/ab/;s/xy/cd/'
Tcl有一个内置的这个
$ tclsh % string map {ab bc bc ab} abbc bcab
这是通过在string中一次一个字符地进行string比较而开始的。
在perl中:
perl -E ' sub string_map { my ($str, %map) = @_; my $i = 0; while ($i < length $str) { KEYS: for my $key (keys %map) { if (substr($str, $i, length $key) eq $key) { substr($str, $i, length $key) = $map{$key}; $i += length($map{$key}) - 1; last KEYS; } } $i++; } return $str; } say string_map("abbc", "ab"=>"bc", "bc"=>"ab"); '
bcab
这是一个基于oogas sed
echo 'abbc' | awk '{gsub(/ab/,"xy");gsub(/bc/,"ab");gsub(/xy/,"bc")}1' bcab