substitua um caractere de uma string que esteja entre a primeira e a segunda pesquisa usando sed ou awk

substitua um caractere de uma string que esteja entre a primeira e a segunda pesquisa usando sed ou awk

Preciso substituir _(sublinhado) por ?(ponto de interrogação) em um arquivo que contém endereços de e-mail.

O arquivo se parece com abaixo:

EFT_020034-E015133  20140624    /ACC/[email protected]         SHR    END 
EFT_020034-E015133  20140624    /ACC/[email protected]     SHR    END
EFT_020034-E015133  20140624    /ACC/[email protected]        SHR    END

A saída esperada é:

EFT_020034-E015133  20140624    /ACC/[email protected]         SHR    END 
EFT_020034-E015133  20140624    /ACC/[email protected]     SHR    END
EFT_020034-E015133  20140624    /ACC/[email protected]        SHR    END

Como posso fazer isso emsedouestranhosem afetar outros sublinhados e apenas o sublinhado entre EMAIL+(constante) e SHR(constante). O conteúdo alterado deve ser salvo em um novo arquivo.

Responder1

awk fará isso:

$ awk '{ gsub("_", "?", $3) ; print }' < data
EFT_020034-E015133 20140624 /ACC/[email protected] SHR END
EFT_020034-E015133 20140624 /ACC/[email protected] SHR END
EFT_020034-E015133 20140624 /ACC/[email protected] SHR END

Os endereços de e-mail estão no campo 3, portanto substituímos _por ?apenas no campo 3, inclusive quando houver mais de um _, usandogsub.

Responder2

Com sedvocê poderia fazer:

sed -e :1 -e 's/_\([^+]*@\)/?\1/;t1'

Isso é substituir _seguido por uma sequência de não- +caracteres seguida por @com ?a sequência de caracteres e repetir o processo desde que corresponda.

Ou fazer isso apenas entre EMAIL+e SHR:

sed -e :1 -e 's/\(EMAIL+.*\)_\(.*SHR\)/\1?\2/;t1'

Se você quiser considerar apenas as linhas que começam com ^EFT, você pode adicionar um -e '/^EFT/!b'para deixar de lado aquelas que não gostam:

sed -e '/^EFT/!b' -e :1 -e 's/\(EMAIL+.*\)_\(.*SHR\)/\1?\2/;t1'

Observe que para uma entrada como:

EFT EMAIL+ foo_bar SHR bar_baz EMAIL+ SHR

Ambos os sublinhados serão substituídos porque estão entre an EMAIL+e a SHR.

Para evitar isso, você poderia fazer algo como:

sed '
  /^EFT/!b # leave the non-EFT lines alone (branch out)
  s/%/%p/g; s/</%l/g; s/>/%r/g; # escape the <>% characters with %
  s/EMAIL+/</g; s/SHR/>/g; # replace EMAIL+ and SHR with < and >
  :1
  s/\(<[^<>]*\)_\([^<>]*>\)/\1?\2/; t1
  s/</EMAIL+/g; s/>/SHR/g; # restore EMAIL+ and SHR
  s/%r/>/g; s/%l/</g; s/%p/%/g; # restore the escaped <>%'

Responder3

sed '/.*EMAIL+\(.*\)SHR.*/{
    h;s//\1/;y/_/?/;G
    s/\(.*\)\n\(.*EMAIL+\).*SHR/\2\1SHR/}'

Isso deve fazer o trabalho de maneira bastante confiável - substituirá tudo _entre ?o último EMAIL+ocorrido em uma linha e o último SHRocorrido na mesma e somente nas linhas que contêm ambas as strings.

informação relacionada