Estou transformando alguns dados com awk
(ou gawk
) e quero deletar um dos campos de entrada antes de imprimir a saída novamente.
O que eu quero alcançar é isso:
~ $ echo 'field1,field2,field3' | awk -F, '{transform($1); delete($2); print $0;}'
new_field1,field3
Não posso simplesmente atribuir uma string vazia a $2
porque isso leva a new_field1,,field3
(observe as duas vírgulas).
Eu poderia imprimir explicitamente apenas os campos que desejo, mas isso não é muito elegante porque tenho muito mais campos do que 3 e também há campos opcionais no final (não mostrados aqui). Por isso prefiro print $0
. Só precisa se livrar de alguns campos primeiro.
Qualquer ideia?
Excluir campos no awk é notoriamente difícil. Parece ser uma operação tão simples (e muitas vezes necessária), mas é mais difícil do que deveria ser.
Consulte Existe uma maneira de excluir completamente os campos no awk, para que os delimitadores extras não sejam impressos? do Stack Overflow para uma boa maneira de fazer isso.
Copiei a
rmcol()
função na resposta de @ghoti, para que tenhamos uma cópia aqui no U&L:Ele exclui a coluna especificada da linha de entrada atual e diminui o contador de campo (
NF
) para corresponder.Não tenho ideia do que sua
transform()
função faz, então nem tentarei duplicar isso - mas aqui está um exemplo de usormcol()
em umaawk
linha:BTW, se você precisar excluir vários campos de uma linha de entrada, é melhor/mais fácil excluí-los na ordem inversa. Ou seja, exclua primeiro os campos com os números mais altos . Por quê? Como os campos de numeração mais alta serão renumerados toda vez que você excluir um campo de numeração mais baixa, tornando muito difícil acompanhar qual número de campo pertence a qual campo.
BTW,
delete()
inawk
é para excluir elementos de uma matriz - não para excluir campos de uma linha de entrada. Você poderiasplit()
inserir cada linha de entrada (onFS
) em uma matriz e excluir o segundo elemento da matriz, mas teria que escrever umajoin()
função para imprimir a matriz com uma vírgula (ouOFS
) separando cada campo.Mesmo fazer isso seria mais complicado do que seria de esperar, porque todos os arrays
awk
são arrays associativos (ou seja, eles não são indexados numericamente) - portantodelete(array[2])
, não mudará automaticamente os elementos do array 3+ para os elementos 2+. Você teria que escrever sua própria função wrapperdelete()
para fazer praticamente a mesma coisa para arrays quermcol()
faz para campos de entrada.Algumas alternativas
1) pré-processar a entrada para remover o campo primeiro, fácil de fazer
cut
se o separador de campo for de um único caractere2) usar
perl
Reescrever $0 com
gensub
pode resultar em scripts mais simples.Para remover os campos 2 e 3 de uma determinada entrada, você pode remover os campos de $0 usando
gensub
e regenerar $0 (e, portanto, todos os campos) da seguinte maneira:Note que
print
é equivalente aprint $0
.