Você pode usar este simples sed
.
sed 's/\w*_\s*//;/^$/d' infile.txt
/^$/d
excluirá as linhas vazias nas quais a linha inclui apenas um campo que termina com sublinhado foo_
ou _
sozinho.
Resultado:
357M
154=
419X 34=
Eu tenho file1
contendo vários campos separados por tabulações, nos quais eu gostaria de remover apenas os campos contendo uma string específica, no meu caso o caractere de sublinhado _
(não removendo toda a linha):
cat file1
357M 2054_
357_ 154= 1900_
511_ 419X 1481_ 34=
Gostaria de obter o seguinte:
cat file2
357M
154=
419X 34=
Consegui remover os campos da seguinte forma:
cat file1 | perl -pe 's/\w+_\s*//g'
357M 154= 419X 34=
Mas o formato não é bom, porque eu gostaria de não alterar o número de colunas.
Eu também tentei:
cat file1 | sed 's/[0-9]*_//g'
357M
154=
419X 34=
Mas eu gostaria de me livrar dessas colunas vazias.
Uma abordagem de força bruta que também funciona:
cat file1 | sed 's/[0-9]*_//g' | tr -s '\t' '\t' | sed 's/^[ \t]*//g'
357M
154=
419X 34=
Este último comando: (1) remove todos os campos que contêm um sublinhado; (2) substitui várias guias em uma linha com apenas uma guia; (3) remove as guias principais. Não é tão elegante assim.
Alguma sugestão?
Considere:
sed 's/[^\t]*_//; s/\t[^\t]*_/\t/g' < input
Isso realiza duas substituições (condicionais):
A primeira pesquisa é necessária para encontrar os campos principais que devem ser removidos; o segundo varre o resto.
Isso deixa os campos originais em suas colunas:
357M
154=
419X 34=
Para remover completamente os campos, basta incluir as guias no texto de pesquisa e substituição:
sed 's/[^\t]*_\t//; s/\t[^\t]*_//g' < input
Resultados em:
357M
154=
419X 34=
Existe sempre a abordagem da "força bruta e ignorância".
Não é inteligente, não é inteligente, mas funciona.
A seguir, TAB significa o caractere TAB literal
sed -e 's/[0-9]*_//g' -e 's/TABTAB/TAB/g' -e 's/^TAB//' -e 's/TAB$//'
por exemplo
$ cat x
357M 2054_
357_ 154= 1900_
511_ 419X 1481_ 34=
$ sed -e 's/[0-9]*_//g' -e 's/ / /g' -e 's/^ //' -e 's/ $//' < x
357M
154=
419X 34=
awk
:
awk 'a=""; {for(i=1; i<=NF; ++i) {if($i ~ /[MX=]$/) a=(a?a"\t":"")$i}; \
if(a) print a}' file.txt
a=""
define a variável a
como nulo para o registro atual, ou seja, tornando a
específico do registro
for(i=1; i<=NF; ++i) {if($i ~ /[MX=]$/) a=(a?a"\t":"")$i}
itera nos campos, verifica se o campo está terminando em M
ou X
ou =
, se assim for, adiciona o campo à variável a
com uma guia para separação entre qualquer salve previamente o campo
if(a) print a
imprime a
se não for nulo
Golfed:
awk 'a="";{for(i=1;i<=NF;++i)if($i~/[MX=]$/)a=(a?a"\t":"")$i;if(a)print a}'
Exemplo:
% cat file.txt
357M 2054_
357_ 154= 1900_
511_ 419X 1481_ 34=
% awk 'a=""; {for(i=1; i<=NF; ++i) {if($i ~ /[MX=]$/) a=(a?a"\t":"")$i}; if(a) print a}' file.txt
357M
154=
419X 34=
Isso seria um pouco mais fácil se você estivesse preocupado apenas com os campos interiores (isto é, não o primeiro ou último campo em uma linha). Mas você quer olhar para todos os campos. Então eu tenho uma solução que faz parecer que não estamos lidando o último campo em cada linha:
sed -e 's/$/\t/' -e 's/[^\t]*_[^\t]*\t//g' -e 's/\t$//'
Isso
_
e os remove, e a seguinte guia, substituindo-os por nada.
Isso funciona no campo n th (ou seja, o último campo na linha original)
porque o passo 1 adicionou um separador no final. Isso tem o recurso (que eu sei que você não pediu, mas você pode gostar de ver que ele está disponível) que preserva campos nulos:
$ cat file3 The brown jumps the dog. quick fox over lazy Four and_ years score seven ago... $ (the_above_command) file3 The brown jumps the dog. quick fox over lazy Four years score seven ago...
P.S. Dependendo de qual versão de sed
você tem,
talvez seja necessário digitar as guias reais no comando em vez de \t
.
Ou, se você estiver usando o bash,
você pode usar $'…'
para as sequências de comandos sed
que contêm \t
.
Tags text-processing perl sed