![仅当匹配项构成整个单词时,如何才能查找和替换?](https://linux22.com/image/47864/%E4%BB%85%E5%BD%93%E5%8C%B9%E9%85%8D%E9%A1%B9%E6%9E%84%E6%88%90%E6%95%B4%E4%B8%AA%E5%8D%95%E8%AF%8D%E6%97%B6%EF%BC%8C%E5%A6%82%E4%BD%95%E6%89%8D%E8%83%BD%E6%9F%A5%E6%89%BE%E5%92%8C%E6%9B%BF%E6%8D%A2%EF%BC%9F.png)
我的脚本是:
n="y"
while [ "{n}" = "y" ]
if [ $n == "n" ];
then
break;
fi
echo "n is $n"
do
read -p "Enter the word to find = " word
read -p "Enter word to replace = " replace
echo "$word n $replace"
#sed -i r.text.bak 's/$word/$replace/g' r.txt
sed -i "s/$word/$replace/g" "test.txt"
echo "do you have further replacement? n or y"
read temp
n=$temp
done
我的问题是我也替换了部分匹配项。例如,对于这样的一行:
1.1.1.14 1.1.1.14567
我得到这个输出:
1.1.1.3 1.1.1.3567
但我期望:
1.1.1.3 1.1.1.14567
我该如何解决这个问题?
答案1
您需要以仅匹配整个单词的方式编写正则表达式。使用 GNU sed
,您可以\b
在单词边界使用 which 匹配:
sed -i "s/\b$word\b/$replace/g"
如果您知道那里总会有一个空格,您可以添加一个空格:
sed -i "s/ $word /$replace/g"
现在,您的脚本也存在一些问题。你的if ... break
说法没有用,他们while
已经在处理这个问题了。所有你需要的是:
#!/usr/bin/env bash
n="y"
while [ "$n" = "y" ]
do
echo "n is $n"
read -p "Enter the word to find = " word
read -p "Enter word to replace = " replace
echo "$word n $replace"
sed -i "s/\b$word\b/$replace/g" test.txt
echo "do you have further replacement? n or y"
read temp
n="$temp"
done
答案2
替换脚本中的以下行
sed -i "s/$word/$replace/g" "test.txt"
和
sed -i "s/$\bword\b/$replace/g" test.txt
请参考以下链接。 http://www.rexegg.com/regex-boundaries.html#wordboundary
答案3
在这里,我会使用perl
.
WORD=$word REPLACE=$replace perl -pi -e '
s/\b\Q$ENV{WORD}\E\b/$ENV{REPLACE}/g' file
sed
(甚至 GNU sed
)没有\Q\E
您需要的等效项,以免$word
被视为正则表达式。大多数sed
实现不支持-i
(或者它们以不同的语法支持)或\b
.
\b
匹配 a 之间的转换单词和非词特点。
所以仍然会\b\Q1.1.2.3\E\b
匹配1.1.2.3.4
.
非词。
你还可以这样做:
WORD=$word REPLACE=$replace perl -pi -e '
s/(?<!\S)\Q$ENV{WORD}\E(?!\S)/$ENV{REPLACE}/g' file
$word
只要前面或后面没有非空格字符就匹配。 (使用(?<!)
和(?!)
否定向后/向前运算符)。
请注意,perl
默认情况下将使用 ASCII 字符。例如,一个单词字符只能是_a-zA-Z0-9
(\b\Q1.2.3\E\b
将匹配1.2.3é
并\S
匹配扩展 unicode 间距字符的各个字节)。对于非 ASCII 数据,您可能希望将该-CLSD
选项添加到perl
.
一些例子:
$ export WORD=1.1.1.3 REPLACE=REPLACE
$ printf '1.1.1.3-x 1.1.1.3\u2006 1.1.1.3.4 1.1.123 1.1.1.3\u20dd 1.1.1.3\ue9\n' > f
$ cat f
1.1.1.3-x 1.1.1.3 1.1.1.3.4 1.1.123 1.1.1.3⃝ 1.1.1.3é
$ perl -pe 's/\b\Q$ENV{WORD}\E\b/$ENV{REPLACE}/g' f
REPLACE-x REPLACE REPLACE.4 1.1.123 REPLACE⃝ REPLACEé
$ perl -CLSD -pe 's/\b\Q$ENV{WORD}\E\b/$ENV{REPLACE}/g' f
REPLACE-x REPLACE REPLACE.4 1.1.123 1.1.1.3⃝ 1.1.1.3é
$ perl -pe 's/(?<!\S)\Q$ENV{WORD}\E(?!\S)/$ENV{REPLACE}/g' f
1.1.1.3-x 1.1.1.3 1.1.1.3.4 1.1.123 1.1.1.3⃝ 1.1.1.3é
$ perl -CLSD -pe 's/(?<!\S)\Q$ENV{WORD}\E(?!\S)/$ENV{REPLACE}/g' f
1.1.1.3-x REPLACE 1.1.1.3.4 1.1.123 1.1.1.3⃝ 1.1.1.3é
$ sed "s/\b$WORD\b/$REPLACE/g" f
REPLACE-x REPLACE REPLACE.4 REPLACE REPLACE⃝ 1.1.1.3é
答案4
sed -i "s/\s$word\s/$replace/g" "test.txt"
sed 还支持元字符\s
例子
var=world
echo "hello world"|sed -r "s/\s$var(\s|$)/.../g"
结果
hello...
请注意,有必要放置(\s|$)
模式,因为一行可以以单词结尾,后跟行尾字符而不是空格