awk - alguns exemplos de uso, scripts e linha de comando

Atualizado em: 04/09/2006



Sobre este documento

linhas de comando e scripts com uso do awkq, espaço para minhas colinhas sobre awk.

O que significa awk?

Awk é uma linguagem com muitas funcionalidades, excelente na manipulação de strings e arquivo texto, muito útil pra usar na linha de comando, em scripts, em combinação com outros aplicativos como cat, ls e etc...

Definição em: awk -info, retorna.

  gawk é uma linguagem de processamento e busca de padrões.
  Por padrão, o gawk lê a entrada padrão e escreve na saída padrão.

awk é uma linguagem, simples mas poderosa, para manipular arquivos de dados (e mais). Por exemplo, sendo data.dat seu arquivo de dados multi-campos.

$ awk '$2 ~ "abc" {print $1, "\t", $4}' data.dat

imprime os campos 1 e 4 de cada linha de data.dat cujo segundo campo contenha "abc".

O awk é perfeito pra tarefas em arquivos formatados em colunas, pode usar print $X onde X é a coluna a ser impressa, pode aplicar diretamente em um arquivo texto ou no resultado de comandos passado pelo pipe "|"

Digite na caixa de pesquisa do www.google.com.br, define:awk

pesquise também por gawk, define:gawk

Tradutor do google.

http://translate.google.com/translate_t

CTRL+T abre outra aba no browser para colar a URL que deseja traduzir.

Já que está procurando no google, aproveite e faça a pesquisa, coloque o termo que procure e acrescente +awk ~linux, exemplo para apagar linha:

apagar linha +awk ~linux

AWK faz parte da maioria das distro, caso não instalou ou removeu, para instalar procure pelo pacote; awk ou gawk

Ajuda:

     Man awk
     awk --help
     gawk --help

Algumas sugestões de pesquisa no Google:

    Re: awk ~linux
    awk ~linux
    how to awk ~linux
    define:awk

Dicas

$0 Pode ser um arquivo inteiro, registro completo, linha corrente completa. Indica e representa tudo, isto depende do que o awk está tratando.

Exemplo para imprimir o arquivo de senhas.

awk '{ print $0 }' /etc/passwd

Tem o mesmo resultado de: cat /etc/passwd

Imprimir somente usuários com UID igual a 1.000 ou maior.

awk -F: '$3 > 999 {print $0}' /etc/passwd

$1 $2 ... indica o campo, onde $1 é referencia ao campo 1, $2 campo 2 e assim por diante, isto depende do delimitador utilizado para separar os campos.

pegar somente o campo 1 do arquivo de usuários.

awk -F ":" '{print $1}' /etc/passwd

cat /etc/passwd | awk -F ":" '{print $1}'

Campo 1 e 3

awk -F ":" '{print $1,$3}' /etc/passwd

delimitadores

man awk

         -F fs
         --field-separator fs
                Use fs for the input field separator (the value of the FS prede-
                fined variable).

usando _ como delimitador

echo "usando_em_lugar_do_ponto_ou_espacos" | awk -F\_ '{print $5 ; }'

Onde;

-F\_ indica o delimitador _, a barra \ funciona como escape para o shell não interpretar o _

print $5 indica para pegar a quinta ocorrencia, neste exemplo retorna "ponto", trocando por 3 (print $3) retorna lugar.

trocando a barra \ por aspas " " para informar o delimitador

echo "usando_em_lugar_do_ponto_ou_espacos" | awk -F"_" '{print $5 ; }'

usando espaço como delimitador

echo "usando em lugar do ponto ou espacos" | awk -F" " '{print $5 ; }'

echo "usando_em_lugar_do_ponto_ou_espacos" | awk -F"_" '{print $5 ; }'

alterar o delimitador _ para espaços e acrescentar (acrescentou) na sexta posição.

echo "usando_em_lugar_do_ponto_ou_espacos" | awk -F"_" '{printf"%s=%s=%s=%s=%s=%sacrescentou=%s\n",$1,$2,$3,$4,$5,$6,$7}'

usando=em=lugar=do=ponto=ouacrescentou=espacos

Alteração em arquivos, colunas, palavras ou linhas

Colunas em arquivos

Manipular arquivo.txt, conteúdo.

  SP lampadas 5.102 130.203    2.155,58     206,45
  RS fluoresc 6.402 130.215      816,45      79.13
  AC lampadas 6.102 129.452    4.421,85       0,00
  RO luminari 6.102 129.854    1.092,15       0,00

Juntar coluna 2 e 3, observe que não tem espaço entre (%s%s), acrescentar a palavra "entregue" depois da coluna 4, formatar as colunas de valores 5 e 6, com 14 caracteres cada e imprimir alinhado à direita, observe que $s imprime na ordem da seleção, o primeiro %s imprime $1, caso queira outra coluna lugar, altere a ordem da seleção das colunas, aqui estão na ordem mas pode alterar para algo como $4,$1,$5. portanto, para alterar a ordem de impressão tem que alterar na ordem da seleção.

  awk -F" " '{printf"%s %s%s %s entregue%14s%14s\n",$1,$2,$3,$4,$5,
  $6}' /tmp/teste/arquivo.txt > /tmp/teste/arqnovo.txt
  
  Conteúdo do arquivo criado (arqnovo.txt
  
  SP lampadas5.102 130.203 entregue      2.155,58        206,45
  RS fluoresc6.402 130.215 entregue        816,45         79.13
  AC lampadas6.102 129.452 entregue      4.421,85          0,00
  RO luminari6.102 129.854 entregue      1.092,15          0,00
     entregue

Imprimir somente as colunas 1 3 5 e 6, faça a seleção dos campos como no exemplo abaixo ($1,$3,$5,$6)

  awk -F" " '{printf"%s %s %14s%14s\n",$1,$3,$5,$6}' /tmp/teste/arquivo.txt > /tmp/teste/arqnovo.txt
  
  cat arqnovo.txt
  SP 5.102       2.155,58        206,45
  RS 6.402         816,45         79.13
  AC 6.102       4.421,85          0,00
  RO 6.102       1.092,15          0,00

No exemplo acima pega a coluna completa, no exemplo abaixa pega uma faixa de caracteres da coluna, ou seja, pega a coluna e depois seleciona parte dela

  awk '{ print substr ($4,5,3)}' /tmp/teste/arquivo.txt > /tmp/teste/arqnovo.txt
  
  cat /tmp/teste/arqnovo.txt
  203
  215
  452
  854
  
  
  Onde:
  ($4,5,3) $4 = igual a coluna do arquivo, altere para coluna desejada.
            5 = posição inicial
            3 = quantidade de caracteres a pegar a partir da da posição 5
                  ou seja, pega da coluna 4 o caracteres entre 5 e 8.

awk + ls

Exemplo com o comando ls -la para listar somente tamanho e nome de arquivo

CL 10

ls -la |awk '{print $5" "$8}'

  1228107776 arquivao.gdb
  52428800 part_aa
  52428800 part_ab
  52428800 part_ac
  52428800 part_ad
  52428800 part_ae
  30668800 part_af

SUSE 10.1

ls -la |awk '{print $5" "$9}'

Onde:

$5 mostra o tamanho do arquivo

$8 mostra o nome do arquivo.

Invertendo a ordem, colocando o $8 primeiro e $5 depois, também vai inverter o resultado na linha, no primeiro exemplo exibe o tamanho do arquivo e depois o nome, com a inversão passa exibir no resultado o nome do arquivo e depois o tamanho, faça um teste com estes exemplos:

ls -la |awk '{print $5" "$8}'

ls -la |awk '{print $8" "$5}'

awk + tail

Listar IP e site.

tail -f /var/log/squid/access.log |awk '{print "IP: "$3" site: "$7}'

O log pode ser diferente conforme a versão do Squid, o exemplo acima funciona no SUSE 10.1, ajuste as colunas "$3" "$7 coforme os logs no seu sistema, altere para usuários ou outra coluna que deseja exibir.

awk + sort

Ordenar uma lista de palavras com sort, neste exemplo, pegar todos usuários em /etc/passew e listar por ordem de nome.

awk -F: '{print $1}' /etc/passwd | sort

Para salvar em aquivo basta acrescentar o redirecionador > e nome do arquivo.

awk -F: '{print $1}' /etc/passwd | sort > arqusers.txt

Listar nome e ID, primeira e terceira coluna do arquivo de senhas. (zago:x:1000), no exemplo abaixo imprime dois espaços entre as colunas, no segundo exemplo inverte a ordem, primeiro o ID e depois o nome.

awk -F: '{print $1 " " $3}' /etc/passwd | sort

awk -F: '{print $3 " " $1}' /etc/passwd | sort

contar tamanho de variáveis, palavras e linhas

length() contar string.

Retorna o número de caracteres do dado recebido, pode ser de uma variável ou de arquivo, por default o espaço é o separador, portanto fique atento, pode retornar contagem de palavras em lugar de linhas, veja alguns exemplos abaixo e faça testes.

contar bytes por coluna ou linha em arquivo

Contar bytes da coluna de um arquivo, no exemplo abaixo altere $1 para o numero da coluna que deseja contar, $0 conta a linha inteira.

awk '{ print length ($1)}' arquivo.txt

cat arquivo.txt | awk '{ print length ($1)}'

$0 conta a linha inteira, contagem por linha, retorna lista com numero de bytes por linha

cat arquivo.txt | awk '{ print length ($0)}'

cat arquivo.txt | awk '{print length($0)}'

MVAR="contar bytes da variável"

echo $MVAR | awk '{print length($0)}'

24

Contar os bytes da segunda palavra.

echo $MVAR | awk '{print length($2)}'

5

MVAR2=`echo $MVAR | awk '{print length($2)}'`

echo $MVAR2

5

pegar a posição inicial da substring

echo $MVAR | awk '{print index($0,"bytes")}' 8 echo $MVAR | awk '{print index($0,"vel")}' 22

converter maiusculo/minuscula

MVAR="TEXTO EM minusculo"

echo $MVAR | awk '{print toupper($0)}'

TEXTO EM MINUSCULO

echo $MVAR | awk '{print tolower($0)}'

texto em minusculo

contar linhas de arquivo

Contador de lilnhas, retorna o numero total de linhas do arquivo informado (arquivo.txt), incluindo as linhas em branco.

NR = numero de registros, ou numero de linhas quando contando as linhas como registro de um arquivo.

awk 'END { print NR }' arquivo.txt

Lista arquivo sem as linhas linhas em branco

awk 'NF>0' arquivo.txt

Eliminar linhas em branco e redirecionar resultado para outro arquivo.

awk 'NF>0' arquivo.txt > arqlimpo.txt

Pegar linha especifica do arquivo

Passar para variável MEUIP o conteúdo da linha 10 do arquivos arqtemp.txt

Esta linha de comando salva o IP da conexão na linha 10 do arquivo arqtemp.txt

lynx -dump http://www.modemclub.com.br/cgi-bin/mostraip.cgi > arqtemp.txt

As duas linhas abaixo; cria a variável com o IP (linha 10) e na linha seguine echo exibe o conteúdo.

MEUIP=`awk 'NR == 10' arqtemp.txt`

echo $MEUIP

Pegar coluna de linha especifica, exemplo da coluna 2 na linha 5

  MMODIF=$(stat /tmp/teste/comandos.txt | awk 'NR == 5 {print $2}' )
  echo $MMODIF
  2006-07-22

converter arquivos e datas

  awk strftime'("%c", systime())'
  awk '{print strftime("%c", systime(),$1)}'

converter data de log do Squid

No inicio da linha de log do Squid aparece um numero semelhante a este

1085173079.594

Exemplo de uma linha de log do Squid.

  1085173079.594     16 192.168.1.46 TCP_MISS/200 2435 GET http://192.168.1.3/programas/ - DIRECT/192.168.1.3 text/html

Este numero representa a data e hora no formato Unix, (Unix Timestamp). Converter esta data para formato legivel (hora humana), por exemplo, nos log do Squid a data vem neste formato: 1085173079.594, o que vem depois do ponto são milesimos de sengundo que não interessa na data, mesmo porque não usamos este formato de tempo, na conversão elimine o ponto e o que vem depois dele.

Com awk, converter e inverter a ordem para indexar por ano mes e dia.

  echo "1085173079" | awk '{print strftime("%F %H:%M:%S",$1)}'
  2004-05-21 17:57:59
  
  echo "1085173079" | awk '{print strftime("%F",$1)}'
  2004-05-21
  echo "1085173079" | awk '{print strftime("%F",$0)}'
  2004-05-21

No exemplo acima a formatação "%F" é uma forma abreviada do comando date, esta opção do date está sendo usada na função strftime do awk, equivale a (%Y-%m-%d) e retorna a data no formato ano-mes-dia, veja o exemplo abaixo com troca de (%F) por (%Y-%m-%d) e obtendo o mesmo resultado.

  echo "1085173079" | awk '{print strftime("%Y-%m-%d %H:%M:%S",$1)}'
  2004-05-21 17:57:59

Para obter a data em outros formatos, altere a formatação como nos exemplos abaixo, observe a troca de "%F" por outros formatos. Para ver todas opções, consulte o man do date (man date). faça testes com todas opções encontradas no manual da date, combine as opções até conseguir o resultado desejado.

  echo "1085173079" | awk '{print strftime("%Y%m%d %H:%M:%S",$1)}'
  20040521 17:57:5
  
  echo "1085173079" | awk '{print strftime("%Y/%m/%d %H:%M:%S",$1)}'
  2004/05/21 17:57:59
  
  echo "1085173079" | awk '{print strftime("%d-%b-%Y %H:%M:%S",$1)}'
  21-Mai-2004 17:57:59

Outro exemplo de conversão com date

date --date='1/1/1970 + <UNIXTIME> seconds'

Converter a data 1085173079.594, execute esta linha de comando:

date --date='1/1/1970 + 1085173079 seconds'

Veja o resultado:

  [zago@faqcl9 zago]$ date --date='1/1/1970 + 1085173079 seconds'
  Sex Mai 21 20:57:59 UTC 2004

Caso ocorra uma diferença de 3 horas é problema com a configuração do locale, no Brasil são 3 horas a menos do que o GMT, acerte isto nas configurações de fuso horario

Outros exemplos

Numerar todas as linhas de arquivo.

NF The number of fields in the current input record.

awk '{print NR" "$0}' arqorigem.txt > arqnumerado.txt

Onde $0 (zero) pega todas as linhas, qualquer numero diferente de zero pega linhas parciais do arquivo.

Indicações

tutoriais em português.

http://br.geocities.com/cesarakg/awk-1.html
http://brlinux.linuxsecurity.com.br/artigos/awk_intro.htm

Manual AWK
http://www.inf.pucrs.br/~manssour/AWK/index.html

Tutorial em espanhol
http://www.ciberdroide.com/misc/novato/curso/awk1.html

Página principal sobre script em geral (FAQ)
http://www.zago.eti.br/script/A-menu-scripts.html

Página principal deste site (FAQ)
http://www.zago.eti.br/menu.html