awk

awk [padrão ação textos]

Descrição

  • A linguagem de programação AWK permite a manipulação de textos a partir de uma sequência de padrões. É uma linguagem interpretada (não há necessidade de compilação).
  • O nome AWK vem dos sobrenomes dos três criadores da linguagem: Alfred V. Aho, Peter J. Weinberger e Brian W. Kernighan.

Algumas opções do comando

  • -f : especifica o nome do arquivo com os comandos a serem executados.
  • -F : define quem é o separador de campos (o padrão é o espaço).
  • -h ou −−help : informa as opções do utilitário.
  • -V ou −−version : informa a versão do utilitário.

Exemplos

  • Suponha que queremos obter a lista dos usuários do sistema e o shell usado por cada um dos usuários. Estas duas informações fazem parte do arquivo /etc/passwd onde existe uma entrada para cada usuário do sistema com as seguintes informações: nome, senha, UID, GID, informações do usuário, diretório home e o shell padrão. Por exemplo, a linha abaixo mostra a entrada para o usuário aluno que usa o shell bash como padrão.

aluno:x:1001:1001::/home/aluno:/bin/bash

Note que os campos são separados por dois pontos (“:”). Podemos então, digitar o seguinte comando para obter os nomes e os shells dos usuários:

awk -F:  ‘{print $1 ” => ” $7}’  /etc/passwd

A opção -F define o caractere “:” como separador dos campos. O comando print define a exibição de três argumentos: o primeiro campo de cada linha ($1), a string ” => ” e o sétimo campo de cada linha ($7). Portanto, a saída do comando acima para a entrada do usuário aluno é

aluno => /bin/bash

  • Também podemos executar o comando abaixo para obter o mesmo resultado do exemplo anterior.

awk -F: -f lista_usu /etc/passwd

onde lista_usu é um arquivo texto com o seguinte conteúdo

{print $1 ” => ” $7}

  • Outra forma é criar um arquivo e torná-lo executável com o comando chmod. Por exemplo, suponha que o arquivo teste possui o conteúdo mostrado abaixo. Note que agora o separador de campos é definido na variável FS (Field Separator) e que uma frase é exibida antes de processar o arquivo de entrada (bloco BEGIN) e outra frase é exibida no final da execução (bloco END). Apenas os comandos do bloco central são executados de forma repetitiva (ler uma linha do arquivo de entrada e executa o bloco central). Portanto, neste exemplo, o número de vezes que o comando print do bloco central é executado depende do número de linhas do arquivo /etc/passwd usado como entrada.

#!/usr/bin/awk -f
BEGIN { FS=”:”; print “*** inicio ***\n” }
    {
       print $1 ” => ” $7
    }
END { print “*** fim ***” }

Antes de executá-lo, devemos alterar a permissão do arquivo comchmod u+x testeEm seguida, basta digitar

./teste /etc/passwd

O resultado será o mesmo dos dois primeiros exemplos, exceto que aparecerão duas frases: uma no início e outra no fim da execução.

Mais Exemplos

  • O exemplo abaixo exibe o resultado da soma de dois valores recebidos na linha de comandos. Da mesma forma da função main( ), as variáveis ARGC e ARGV contém, respectivamente, o número de parâmetors e os argumentos passados na linha de comandos (o parâmetro ARGV[0] possui “awk”). Observe que todos os comandos estão dentro do bloco BEGIN (isto significa que os comandos serão executados uma única vez).

#!/usr/bin/awk -f
BEGIN {
    if (ARGC != 3)
       print “Forneca 2 numeros\n”
    else
       {
          soma=ARGV[1]+ARGV[2]
          print “Soma = ” soma
       }
}

  • Abaixo é apresentado um exemplo que calcula o fatorial de um número passado na linha de comandos.

#!/usr/bin/awk -f
BEGIN {
    fat = 1
    for (i = 1; i <= ARGV[1]; i++)
       fat = fat * i
    print “Fatorial de ” ARGV[1] ” = ” fat
}

  • O exemplo abaixo calcula a raiz quadrada de um número. Note que o programa verifica se o parâmetro passado pelo usuário é realmente um número.

#!/usr/bin/awk -f
BEGIN {
    if (ARGC != 2 )
       print “Forneca um numero”
    else
       {
          if (ARGV[1] ~ /^[0-9]+$/)
             {
                raiz=sqrt(ARGV[1])
                print “Raiz quadrada de”, ARGV[1], “=”, raiz
             }
          else
             print “Valor nao numerico”
       }
}

  • Um exemplo de uso de arrays é mostrado a seguir. Note que o índice do array não precisa ser um valor numérico.

#!/usr/bin/awk -f
BEGIN {
    vetor[0] = 1
    vetor[1] = 2
    vetor[2] = 3
    dicionario[“teste”] = “socorro”
    dicionario[“AOU”] = “Linux”
    for (i = 0; i < 3; i++)
       print “vetor[” i “] = ” vetor[i]
    print “teste = ” dicionario[“teste”]
    print “AOU = ” dicionario[“AOU”]
}

  • O exemplo abaixo mostra outra forma de ler o arquivo /etc/passwd e exibir o nome do usuário (primeiro campo = $1) e o shell usado pelo usuário (sétimo campo = $7). Os nomes dos usuários são usados como índices do vetor e cada posição do vetor armazena o shell do usuário. A variável NF contém o número de campos da linha que, neste caso, é igual a 7.

#!/usr/bin/awk -f
BEGIN { FS=”:” }
{
    usuario[$1]=$NF
}
END {
    for (i in usuario)
       print i,”=>”, usuario[i]
}

  • O programa teste mostrado abaixo faz a multiplicação de duas matrizes armazenadas em arquivos distintos (os nomes dessas matrizes são fornecidos na linha de comandos). Observe que o comando getline, usado para ler uma linha de arquivo, retorna 1 quando é executado com sucesso e zero quando nenhuma linha é lida. Neste caso, $0 corresponde à linha toda lida, $1 corresponde ao primeiro campo da linha, $2 ao segundo campo da linha, e assim por diante.

#!/usr/bin/awk -f
BEGIN{
    # Ler primeira matriz
    valor = getline < ARGV[1]
    lin_A = 0
    while (valor == 1)
       {
          lin_A++
          for (i = 1; i <= NF; i++)
             A[lin_A][i] = $i
          valor = getline < ARGV[1]
       }
    col_A = NF
    # Ler segunda matriz
    valor = getline < ARGV[2]
    lin_B = 0
    while (valor == 1)
       {
          lin_B++
          for (i = 1; i <= NF; i++)
             B[lin_B][i] = $i
          valor = getline < ARGV[2]
       }
    col_B = NF
    if (col_A != lin_B)
       printf “Numero de colunas de A dever ser igual a numero de linhas de B\n”
    else
       {
          for (i = 1; i <= lin_A; i++)
             {
                for (j = 1; j <= col_B; j++)
                   {
                      C[i][j] = 0;
                       for (k = 1; k <= col_A; k++)
                           {
                              C[i][j] += A[i][k] * B[k][j]
                           }
                       printf C[i][j] ” ”
                   }
                printf “\n”
             }
       }
}

Suponha que o arquivos A e B tenham os conteúdos mostrados abaixo.

Arquivo A
1  3  1
2  3  2

Arquivo B
2  1
3  1
1  2

Ao executar o programa com

./teste A B

o AWK fornece a seguinte resposta:

12  6
15  9

Variáveis internas

O AWK possui variáveis internas que podem ser usadas pelo programador. A tabela abaixo mostra algumas dessas variáveis.

Variável Descrição
ARGC Número de argumentos da linha de comandos
ARGV Vetor com os argumentos da linha de comandos
ENVIRON Vetor com as variáveis de ambiente
ERRNO Armazena mensagem de erro
FILENAME Nome do arquivo de entrada sendo processado no bloco central
FNR Número de linhas já processadas de um determinado arquivo
FS Separador dos campos da linha de entrada (o espaço é o padrão)
NF Número de campos na linha sendo processada
NR Número de linhas já processadas considerando todos os arquivos de entrada

Observações

  • A linguagem AWK é muito rica pois permite, por exemplo, o uso de
    • comandos de decisão (if, else);
    • laços (for, while, do while);
    • expresões aritméticas (+, -, *, /, %, ++, −−, =, +=, -=, >, >=, <, <=, !=, etc);
    • funções (exp, log, sqrt, split, substr, getline, etc);
    • variáveis, constantes e vetores.

    Para obter mais informações, consulte o manual on-line (digite “man awk”).

  • O mawk é o interpretador para a linguagem AWK. Veja o site oficial do mawk ou consulte o manual on-line.
  • O gawk é é a implementação do Projeto GNU para a linguagem AWK. Veja o site oficial do projeto gawk ou consulte o manual on-line.

 

Sumário      |      Topo