Valores separados por tabulação em awk

89

Como seleciono a primeira coluna da string separada por TAB?

# echo "LOAD_SETTLED    LOAD_INIT       2011-01-13 03:50:01" | awk -F'\t' '{print $1}'

O exemplo acima retornará a linha inteira e não apenas "LOAD_SETTLED" como esperado.

Atualizar:

Preciso alterar a terceira coluna nos valores separados por tabulação. O seguinte não funciona.

echo $line | awk 'BEGIN { -v var="$mycol_new" FS = "[ \t]+" } ; { print $1 $2 var $4 $5 $6 $7 $8 $9 }' >> /pdump/temp.txt

No entanto, isso funciona conforme o esperado se o separador for vírgula em vez de tabulação.

echo $line | awk -v var="$mycol_new" -F'\t' '{print $1 "," $2 "," var "," $4 "," $5 "," $6 "," $7 "," $8 "," $9 "}' >> /pdump/temp.txt
Shantanuo
fonte
4
awk 'BEGIN {FS = "[\ t] +"}; {print $ 1} '# isto é o que eu estava procurando. Minha pesquisa no google está correta? :)
shantanuo
2
Graças a este comentário, descobri: awk 'BEGIN {FS="\t"}; {print $1,FS,$2,FS,$3}' myFile.txtimprimir valores delimitados por tabulação das três primeiras colunas.
Wok
6
Ou talvez simplesmenteawk 'BEGIN {OFS="\t"}; {print $1,$2,$3}'
Josiah Yoder
3
Ambos GNU e BSD awk suportam -vpara definir variáveis. É feio para usar BEGIN {FS="\t"}dentro de um programa embutido , e qualquer contribuição de código aberto que você tente fazer assim provavelmente será contestada. Faça isso apenas se estiver gravando um arquivo de programa . Além disso, é desencorajado usar em -Fvez de -v FS=porque o último deixa claro que apenas FSestá sendo definido e não OFS. A confusão sobre esse último ponto é o que causou esta postagem em primeiro lugar. É por isso que o "bom estilo" é importante.
Bruno Bronosky,
1
Por favor, ninguém, jamais, deve fazer o que @Wok demonstrou. Você não enumera separadores de campo [entrada] em sua saída. Você especifica um separador de campo de saída por meio da OFSvariável.
Bruno Bronosky,

Respostas:

138

Você precisa definir a OFSvariável (separador de campo de saída) para ser uma guia:

echo "$line" | 
awk -v var="$mycol_new" -F $'\t' 'BEGIN {OFS = FS} {$3 = var; print}'

(certifique-se de citar a $linevariável na instrução echo)

glenn jackman
fonte
6
Qual é o propósito de $ em $ '\ t'?
Amr Mostafa
10
Respondendo minha própria pergunta do Advanced Bash Scripting Guide : A construção de expansão de string entre aspas $ '...' é um mecanismo que usa valores octais ou hexadecimais de escape ..., por exemplo, quote = $ '\ 042'.
Amr Mostafa
4
@AmrMostafa, muito ruim que o guia tem uma explicação enganosa levando a pensar que você não o $de $'\t'não é necessário. O wiki de Greg é melhor: "Destes, $'...'é o mais comum e atua como aspas simples, exceto que as combinações com escape de barra invertida são expandidas conforme especificado pelo padrão ANSI C".
Cristian Ciupitu
9
Em retrospectiva, o $'\t'não é necessário. awk entende a string "\t"como um caractere de tabulação
glenn jackman
5
Colaboradores de código aberto, eu imploro, por favor, não envie coisas como awk -F $'\t' 'BEGIN {OFS = FS} …'. Isso deveria ser awk -v FS='\t' -v OFS='\t' '…'. Pode parecer pedante, mas ser inconsistente aumenta as chances de que um colaborador posterior introduza um bug por interpretar mal seu código.
Bruno Bronosky,
21

Certifique-se de que são realmente guias! No bash, você pode inserir uma guia usandoC-v TAB

$ echo "LOAD_SETTLED    LOAD_INIT       2011-01-13 03:50:01" | awk -F$'\t' '{print $1}'
LOAD_SETTLED
Mahmoud Abdelkader
fonte
8

Eu uso as variáveis FSe OFSpara manipular arquivos de zona BIND que são delimitados por tabulação. Aqui está um dos meus scripts https://gist.github.com/RichardBronosky/abe1652c2d5c78c35b92ad02bdf0d0af#file-dns_update-sh-L36-L39

A essência disso é:

awk -v FS='\t' -v OFS='\t' \
    -v record_type=$record_type \
    -v hostname=$hostname \
    -v ip_address=$ip_address '
$1==hostname && $3==record_type {$4=ip_address}
{print}
' $zone_file > $temp

Esta é uma maneira limpa e fácil de ler para fazer isso.

Bruno Bronosky
fonte
5
echo "LOAD_SETTLED    LOAD_INIT       2011-01-13 03:50:01" | awk -v var="test" 'BEGIN { FS = "[ \t]+" } ; { print $1 "\t" var "\t" $3 }'
Shantanuo
fonte
0

Isso não deveria funcionar?

echo "LOAD_SETTLED    LOAD_INIT       2011-01-13 03:50:01" | awk '{print $1}'
Asadz
fonte