Altera as palavras conhecidas 1 e 3 de uma string enquanto mantém a palavra desconhecida 2 constante

0

Eu tenho um arquivo de texto e estou tentando encontrar todas as instâncias de Word1 Word2 Word3 em um arquivo de texto e substituí-lo por Word4 Word2 Word5 . Word2 é uma string desconhecida, mas o resto das palavras é conhecido.

Aqui está o que eu tentei até agora

Eu tenho uma string (...) foobarfoo (...) e quero substituí-la por (...) hatbarcar (...)

sed -i 's/foo.*foo/hat.*car/g' data.txt

mas o resultado que obtenho é

(...) hat.*car (...)

Assim, o caractere curinga é encontrar a palavra que eu quero, mas eu quero usar esse mesmo curinga para escrever a string que substitui a antiga.

Isso é possível / alguém tem alguma sugestão?

    
por JHS 12.09.2017 / 11:01

3 respostas

2

O problema com um

sed -i 's/foo\(.*\)foo/hatcar/g'
A abordagem

é que ela alteraria fooxfoo fooyfoo para hatxfoo fooycar , pois .* é ganancioso.

Você pode usar perl com seu operador .*? não-ganancioso.

perl -i -pe 's/foo(.*?)foo/hat$1car/g'

(que também tem a vantagem de ser mais portátil. Esse -i vem de perl e não está disponível em muitas implementações de sed (e quando é, não é interpretado da mesma forma por todos)). / p>

Com o GNU sed e desde que o $POSIXLY_CORRECT não esteja no ambiente, você poderia fazer:

sed -i 's/foo/\n/g;s/\n\([^\n]*\)\n/hatcar/g;s/\n/foo/g'

Ou seja, substitua foo por um caractere ( \n , o delimitador de linha) que não pode ocorrer na linha, para que possamos usar [^\n]* para obter o equivalente não-ganancioso.

Se POSIXLY_CORRECT estiver no ambiente, [^\n] corresponderia a qualquer caractere, mas \ e n , como POSIX requer, em vez de qualquer caractere, exceto nova linha. Você sempre pode fazer:

(unset -v POSIXLY_CORRECT; exec sed...)

se você quiser que seu script ainda funcione em ambientes em que POSIXLY_CORRECT esteja definido.

    
por 12.09.2017 / 11:22
1

A string de substituição em s/PATTERN/REPLACEMENT/ não é uma expressão regular.

Você poderá capturar o que corresponde a um pouco do padrão e usá-lo no substituto, se desejar:

sed -r 's/foo(.*)foo/hatcar/g' file

Isso irá capturar qualquer coisa entre duas ocorrências de foo na mesma linha e inserir esse bit entre hat e car . O diz "insira qualquer coisa que tenha sido capturada pelos primeiros parênteses".

Observe que .* é "ganancioso", por isso, se você tiver foobarfoofoobarfoo , será barfoofoobar , não bar .

    
por 12.09.2017 / 11:23
0

Com sed, você pode usar \( e \) para criar um grupo de captura que pode ser referenciado como na substituição da substituição:

 sed 's/foo\(.*\)foo/hatcar/g'
    
por 12.09.2017 / 11:17