Como posso encontrar e substituir somente se uma correspondência formar uma palavra inteira?

5

Meu script é:

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

Meu problema é que também estou substituindo correspondências parciais. Por exemplo, para uma linha como esta:

1.1.1.14 1.1.1.14567

Eu recebo esta saída:

1.1.1.3  1.1.1.3567

mas eu esperava:

1.1.1.3 1.1.1.14567

Como posso resolver isso?

    
por dilshan 14.02.2015 / 11:03

4 respostas

7

Você precisa escrever sua expressão regular de uma maneira que corresponda apenas a palavras inteiras. Com o GNU sed , você pode usar \b que corresponde a limites de palavras:

sed -i "s/\b$word\b/$replace/g"

Se você sabe que sempre haverá um espaço lá, basta adicionar um espaço:

sed -i "s/ $word /$replace/g"

Agora, também há alguns problemas com seu script. Sua declaração if ... break é inútil, o while já está cuidando disso. Tudo que você precisa é:

#!/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
    
por 14.02.2015 / 14:16
1

Substitua a seguinte linha no script

sed -i "s/$word/$replace/g" "test.txt"

com

sed -i "s/$\bword\b/$replace/g" test.txt

Por favor se refira a um link seguinte. link

    
por 14.12.2015 / 13:10
0

Aqui, eu usaria perl .

WORD=$word REPLACE=$replace perl -pi -e '
  s/\b\Q$ENV{WORD}\E\b/$ENV{REPLACE}/g' file

sed (mesmo GNU sed ) não tem equivalente para \Q\E , que você precisa aqui para que o $word não seja considerado como um regexp. E a maioria das implementações sed não suportam -i (ou suportam com sintaxe diferente) ou \b .

\b corresponde a uma transição entre um caractere e não-palavra .

Portanto, \b\Q1.1.2.3\E\b ainda corresponderia a 1.1.2.3.4 , pois . é uma não palavra .

Você também pode fazer:

WORD=$word REPLACE=$replace perl -pi -e '
  s/(?<!\S)\Q$ENV{WORD}\E(?!\S)/$ENV{REPLACE}/g' file

Para corresponder em $word desde que não seja precedido nem seguido por um caractere sem espaçamento. (usando (?<!) e (?!) negativo para trás / para frente).

Observe que perl por padrão funcionará com caracteres ASCII. Por exemplo, um caractere palavra seria apenas _a-zA-Z0-9 ( \b\Q1.2.3\E\b corresponderia em 1.2.3é e \S corresponderia a bytes individuais de caracteres de espaçamento unicode estendidos). Para dados não ASCII, você provavelmente desejará adicionar a opção -CLSD a perl .

Alguns exemplos:

$ 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é
    
por 14.12.2015 / 13:50
-2
sed -i "s/\s$word\s/$replace/g" "test.txt"

sed também suporta metacaracteres \s

exemplo

var=world

echo "hello world"|sed -r "s/\s$var(\s|$)/.../g"

resultados

hello...

Note que é necessário colocar o padrão (\s|$) , pois uma linha pode terminar com uma palavra seguida por um caractere de fim de linha em vez de um espaço

    
por 14.02.2015 / 21:25