这是对wef 答案的增强。
我们可以通过删除特殊字符来消除各种特殊字符和字符串(^
, .
, [
, *
, $
, \(
, \)
, \{
, \}
, \+
, \?
,
&
, \1
, ..., 不管什么,以及/
分隔符)的特殊含义问题。
具体来说,我们可以将所有内容都转换为十六进制;那么我们只有0
-9
和 a
-f
来处理。这个例子演示了这个原理:
$ echo -n '3.14' | xxd
0000000: 332e 3134 3.14
$ echo -n 'pi' | xxd
0000000: 7069 pi
$ echo '3.14 is a transcendental number. 3614 is an integer.' | xxd
0000000: 332e 3134 2069 7320 6120 7472 616e 7363 3.14 is a transc
0000010: 656e 6465 6e74 616c 206e 756d 6265 722e endental number.
0000020: 2020 3336 3134 2069 7320 616e 2069 6e74 3614 is an int
0000030: 6567 6572 2e0a eger..
$ echo "3.14 is a transcendental number. 3614 is an integer." | xxd -p \
| sed 's/332e3134/7069/g' | xxd -p -r
pi is a transcendental number. 3614 is an integer.
而,当然,sed 's/3.14/pi/g'
也会改变3614
。
以上是稍微过于简单化了;它不考虑边界。考虑这个(有点做作)的例子:
$ echo -n 'E' | xxd
0000000: 45 E
$ echo -n 'g' | xxd
0000000: 67 g
$ echo '$Q Eak!' | xxd
0000000: 2451 2045 616b 210a $Q Eak!.
$ echo '$Q Eak!' | xxd -p | sed 's/45/67/g' | xxd -p -r
&q gak!
因为$
( 24
) 和Q
( 51
) 结合形成,该命令将其从内部撕开。它变为,即( + <code>71)。我们可以通过用空格分隔搜索文本、替换文本和文件中的数据字节来防止这种情况。这是一个程式化的解决方案:2451
s/45/67/g
2451
2671
&q
26
encode() {
xxd -p -- "$@" | sed 's/../& /g' | tr -d '\n'
}
decode() {
xxd -p -r -- "$@"
}
left=$( printf '%s' "$search" | encode)
right=$(printf '%s' "$replacement" | encode)
encode file.txt | sed "s/$left/$right/g" | decode
我定义了一个encode
函数,因为我使用了该函数 3 次,然后我定义decode
了对称性。如果您不想定义 decode
函数,只需将最后一行更改为
encode file.txt | sed "s/$left/$right/g" | xxd -p –r
请注意,该encode
函数将文件中数据(文本)的大小增加了三倍,然后将其sed
作为单行发送——甚至在末尾没有换行符。GNU sed 似乎能够处理这个问题;其他版本可能做不到。
作为一个额外的好处,这个解决方案可以处理多行搜索和替换(换句话说,搜索和替换包含换行符的字符串)。