Como sed apenas as linhas que contêm determinada string?


13

ENTRADA:

Select ASDF 325 sdfg sdflk lk
Select TRG 46sdg rasdftz fsgs 45
Select ASDF 6ffg sdfg 4456 sdrg

RESULTADO:

Select ASDF 325 XXXX sdflk lk
Select TRG 46sdg rasdftz fsgs 45
Select ASDF 6ffg XXXX 4456 sdrg

Então, resumindo, preciso "sed" "sdfg" para "XXXX".

MAS: somente em linhas que contenham a sequência "Selecionar ASDF". Como posso fazer isso? (sed, awk etc.: \)

Respostas:


19

Você pode prefixar a maioria dos comandos sed com um endereço para limitar as linhas às quais eles se aplicam. Um endereço pode ser um número de linha ou uma expressão regular delimitada por /.

cat INPUT | sed '/Select ASDF/ s=sdfg=XXXX='

Como mencionado Peter.O, o comando conforme escrito acima substituirá a primeira ocorrência de qualquer uma sdfgna string que contém Select ASDF. Se você precisar substituir a correspondência exata sdfgapenas no caso em que está na quarta coluna, siga este caminho:

cat INPUT | sed 's/\(^Select ASDF [^ ]* \)sdfg /\1XXXX /'

1
E quanto a outro campo contendo sdfg ? por exemplo. 5sdfga
Peter.O

Hmm, na verdade esse também não é o problema. Eu atualizei minha resposta.
apressar

existem opções para usar: sed '/ Select ASDF / gs = sdfg = XXXX =' - então eu preciso substituir todas as ocorrências em uma linha, não apenas a primeira. mas sed dá erro se eu usar "g"
LanceBaynes

1
Você precisa digitar gdepois do último =(no final do scomando). Será assim:sed '/Select ASDF/ s=sdfg=XXXX=g'
rush

7

Se você estiver alterando apenas a coluna 4, se ela tiver o valor exato, faz sentido usar operadores de igualdade em vez de expressões regulares.

awk '$1 == "Select" && $2 == "ASDF" && $4 == "sdfg" {$4 = "XXXX"} {print}'

1
Rápido! .. comparando-o, para 1 milhão de linhas, com awk de Birei e do Rush posicional sed: 0m1.580s vs 0m3.792s vs 0m6.740s
Peter.O

1

Usando GNU awk:

awk '
    BEGIN { IGNORECASE = 1 } 
    /^select asdf/ { 
        sub( /\<sdfg\>/, "XXXX", $0 ) 
    } 
    { print }
' infile

Resultado:

Select ASDF 325 XXXX sdflk lk
Select TRG 46sdg rasdftz fsgs 45
Select ASDF 6ffg XXXX 4456 sdrg

ATUALIZAÇÃO : evite IGNORECASEpara um não-GNU awke faça distinção entre maiúsculas e minúsculas. Graças a jw013 , que apontou esse detalhe:

awk ' 
    /^Select ASDF/ { 
        sub( /\<sdfg\>/, "XXXX", $0 ) 
    } 
    { print }
' infile

1
Você deve mencionar IGNORECASEé uma extensão GNU awk/ gawk.
Jw013

1
@ jw013: Obrigado. Resposta atualizada com sua sugestão.
Birei

4
IgnoreCase está errado neste caso, quer se trate do GNU ou G'not .. O critério na questão é explicitamente para maiúsculasASDF
Peter.O
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.