我想用另一个字符串替换文件中找到的字符串,但两者都有一个特殊字符(在本例中它是一个.
字符),例如1.0
和2.0
。
这是当前使用的命令:
sed -i 's/1\.0/2\.0/g' /home/user1/file1.txt
如果1.0
和2.0
保存在变量$i
and中会怎样$j
?哪里i
有价值1.0
,j
有价值2.0
,我还能用什么i
代替j
?
答案1
您可以使用它sed
来为您进行修复:
printf '%s\n' "$i" "$j" |
sed 's/[]\$*&/.^[]/\\&/g;H;$!d
x;y|\n|/|;s|.*|s&/g|' |
sed -f - /path/to/infile
因此,此s///
替换将转义输入中的任何/所有 BRE 元字符:
s/[]\$*&/.^[]/\\&/g
...通过在每个前面加上反斜杠作为前缀。然后,第一个通过在其前面添加 ewline 字符sed
,将第一行 - $i
- 的副本保存在H
旧空间中\n
。$i
然后该行被d
删除,因为它!
不是$
最后一行。下一行 - 该$j
行 - 也是最后一行,在它得到与第一行相同的处理后,它是不是 d
已入选。相反,它会x
更改保持缓冲区和模式缓冲区并对连接的结果进行操作。此时模式空间看起来像:
\n1\.0\n2\.0
...所以我们y///
将所有的\n
行转换为/
斜线,用模式空间本身s///
替换所有的内容,再加上一个前缀和一个后缀,这样我们得到:.*
&
s
/g
s/1\.0/2\.0/g
然后,它会自动打印到第二个sed
正在读取 stdin - 或-f -
- 作为其脚本的文件。当第一个sed
完成并关闭它们之间的管道时,第二个sed
开始应用......
s/1\.0/2\.0/g
...其命名输入文件中的每一行 - 位于此处/path/to/infile
。
我这样写了你的文件:
printf '%04s%04s%04s%04s\n' \
0 0 -1 0 1 0 0 0 0 -1\
0 0 1.5 2.0 1.0 0 >/tmp/temp
这给了我一个像......
0 0 -1 0
1 0 0 0
0 -1 0 0
1.5 2.0 1.0 0
然后我写了一个不同版本的脚本,例如:
ii=0.0
for i in 1.0 2.0 3.0 4.0
do str2=$i
printf '\033[41m## %s \033[0m\n' \
"str2 = $str2" "$ii $str2"
printf %s\\n "$ii" "$str2"
ii=$str2
done |
sed ' s/[]\$^&*./[]/\\&/g;H;x
s|^\(\n\)\(.*\)\n\(.*\)\n\(.*\)\n\(.*\)|\
bs\5\1:i\5\1i\\\1\2\\\1\3\1:s\5\1s/\4/\5/gp;ti\5|p
s|||;h;d' |
sed -f - /tmp/temp
它仅使用 shell 生成字符串,但允许sed
执行所有数据处理。请注意,虽然sed
调用了两个,但每个仅被调用一次。
当我运行它时,结果是:
0 0 -1 0
1 0 0 0
0 -1 0 0
1.5 2.0 2.0 0
## str2 = 2.0
## 1.0 2.0
1.5 3.0 3.0 0
## str2 = 3.0
## 2.0 3.0
1.5 4.0 4.0 0
## str2 = 4.0
## 3.0 4.0
1.5 4.0 4.0 0
以 开头的行#
是红色的,正如我所期望的那样。仅当替换成功sed
时才写入它们。s///
第一个为第二个编写的脚本sed
如下所示:
bs1\.0
:i1\.0
i\
[41m## str2 = 1\.0 [0m\
[41m## 0\.0 1\.0 [0m
:s1\.0
s/0\.0/1\.0/gp;ti1\.0
bs2\.0
:i2\.0
i\
[41m## str2 = 2\.0 [0m\
[41m## 1\.0 2\.0 [0m
:s2\.0
s/1\.0/2\.0/gp;ti2\.0
bs3\.0
:i3\.0
i\
[41m## str2 = 3\.0 [0m\
[41m## 2\.0 3\.0 [0m
:s3\.0
s/2\.0/3\.0/gp;ti3\.0
bs4\.0
:i4\.0
i\
[41m## str2 = 4\.0 [0m\
[41m## 3\.0 4\.0 [0m
:s4\.0
s/3\.0/4\.0/gp;ti4\.0
请注意,虽然看起来字符串[
没有转义,但这只是我的终端对输出的影响 - 它最终会立即吃掉紧随其后的 char \033
。当第二个sed
接收到脚本时,输入是这样的\033\[...
,但它插入到标准输出的输出i
是\033[...
答案2
试试这个:全部转义。将全部替换.
为\.
str1="$( echo -n $i | sed 's/\./\\\./g' )"
对 str2 重复相同的操作$j。然后替换如下
sed "s/$str1/$str2/g"