AWK - AWK

AWK
Paradigma Scripting , procedural , orientado por dados
Projetado por Alfred Aho , Peter Weinberger e Brian Kernighan
Apareceu pela primeira vez 1977 ; 44 anos atrás ( 1977 )
Versão estável
IEEE Std 1003.1-2008 (POSIX) / 1985
Disciplina de digitação Nenhum; pode lidar com strings, inteiros e números de ponto flutuante; expressões regulares
SO Plataforma cruzada
Implementações principais
awk, GNU Awk, mawk, nawk, MKS AWK, Thompson AWK (compilador), Awka (compilador)
Dialetos
antigo awk oawk 1977, novo awk nawk 1985, GNU Awk gawk
Influenciado por
C , sed , SNOBOL
Influenciado
Tcl , AMPL , Perl , Korn Shell ( ksh93 , dtksh , tksh ), Lua

AWK ( awk ) é uma linguagem específica de domínio projetada para processamento de texto e normalmente usada como uma ferramenta de extração de dados e relatório. Como sed e grep , é um filtro e um recurso padrão da maioria dos sistemas operacionais do tipo Unix .

A linguagem AWK é uma linguagem de script baseada em dados que consiste em um conjunto de ações a serem tomadas em relação a fluxos de dados textuais - sejam executados diretamente em arquivos ou usados ​​como parte de um pipeline - para fins de extração ou transformação de texto, como a produção formatada relatórios. A linguagem usa extensivamente o tipo de dados string , arrays associativos (ou seja, arrays indexados por strings de chave) e expressões regulares . Embora o AWK tenha um domínio de aplicativo pretendido limitado e tenha sido especialmente projetado para oferecer suporte a programas de uma linha , a linguagem é Turing-completa , e até mesmo os primeiros usuários do Bell Labs do AWK costumavam escrever grandes programas AWK bem estruturados.

AWK foi criado na Bell Labs na década de 1970 e seu nome é derivado dos sobrenomes de seus autores: Alfred Aho , Peter Weinberger e Brian Kernighan . A sigla é pronunciada da mesma forma que bird auk , que está na capa da The AWK Programming Language . Quando escrito em letras minúsculas, as awk, refere-se ao programa Unix ou Plan 9 que executa scripts escritos na linguagem de programação AWK.

História

AWK foi inicialmente desenvolvido em 1977 por Alfred Aho (autor de egrep ), Peter J. Weinberger (que trabalhou em pequenos bancos de dados relacionais) e Brian Kernighan ; leva o nome de suas respectivas iniciais. De acordo com Kernighan, um dos objetivos do AWK era ter uma ferramenta que manipulasse facilmente números e strings. AWK também foi inspirado na linguagem de programação de Marc Rochkind , usada para pesquisar padrões em dados de entrada, e foi implementado usando yacc .

Como uma das primeiras ferramentas a aparecer na versão 7 do Unix , o AWK adicionou recursos computacionais a um pipeline do Unix além do shell Bourne , a única linguagem de script disponível em um ambiente Unix padrão. É um dos utilitários obrigatórios da Especificação Única do UNIX e é exigido pela especificação Linux Standard Base .

AWK foi significativamente revisado e expandido em 1985–88, resultando na implementação GNU AWK escrita por Paul Rubin , Jay Fenlason e Richard Stallman , lançada em 1988. GNU AWK pode ser a versão mais amplamente implementada porque está incluída com base em GNU Pacotes Linux. GNU AWK foi mantida unicamente por Arnold Robbins desde 1994. Brian Kernigham 's nawk fonte (Nova AWK) foi lançado em 1993 unpublicized, e aberto, desde a década de 1990; muitos sistemas BSD o usam para evitar a licença GPL.

AWK foi precedido por sed (1974). Ambos foram projetados para processamento de texto. Eles compartilham o paradigma orientado a linha e orientado a dados, e são particularmente adequados para escrever programas de uma linha , devido ao loop principal implícito e às variáveis ​​de linha atuais. O poder e concisão dos primeiros programas AWK - notavelmente o poderoso manuseio de expressões regulares e concisão devido a variáveis ​​implícitas, que facilitam one-liners - junto com as limitações do AWK na época, foram inspirações importantes para a linguagem Perl (1987). Na década de 1990, Perl se tornou muito popular, competindo com AWK no nicho de linguagens de processamento de texto Unix.

Estrutura dos programas AWK

POSIX awk.pdf

AWK lê a entrada uma linha por vez. Uma linha é varrida para cada padrão no programa e para cada padrão que corresponde, a ação associada é executada.

-  Alfred V. Aho

Um programa AWK é uma série de pares de ações padrão, escritos como:

condition { action }
condition { action }
...

onde condição é normalmente uma expressão e ação é uma série de comandos. A entrada é dividida em registros, onde por padrão os registros são separados por caracteres de nova linha para que a entrada seja dividida em linhas. O programa testa cada registro em relação a cada uma das condições, por sua vez, e executa a ação para cada expressão verdadeira. A condição ou a ação podem ser omitidas. O padrão da condição é corresponder a todos os registros. A ação padrão é imprimir o registro. Esta é a mesma estrutura de ação padrão do sed.

Além de uma expressão AWK simples, como foo == 1ou /^foo/, a condição pode ser BEGINou ENDfazer com que a ação seja executada antes ou depois de todos os registros terem sido lidos, ou padrão1, padrão2 que corresponde ao intervalo de registros começando com um registro que corresponde ao padrão1 até para e incluindo o registro que corresponde ao padrão2 antes de tentar novamente corresponder ao padrão1 em linhas futuras.

Além dos operadores aritméticos e lógicos normais, as expressões AWK incluem o operador til,, ~que corresponde a uma expressão regular a uma string. Como um açúcar sintático útil , / regexp / sem usar o operador til corresponde ao registro atual; esta sintaxe deriva de sed , que por sua vez a herdou do editor ed , onde /é usada para pesquisa. Essa sintaxe de usar barras como delimitadores para expressões regulares foi posteriormente adotada por Perl e ECMAScript e agora é comum. O operador til também foi adotado por Perl.

Comandos

Os comandos AWK são as instruções que substituem a ação nos exemplos acima. Os comandos AWK podem incluir chamadas de função, atribuições de variáveis, cálculos ou qualquer combinação dos mesmos. AWK contém suporte integrado para muitas funções; muitos mais são fornecidos pelos vários sabores de AWK. Além disso, alguns sabores suportam a inclusão de bibliotecas vinculadas dinamicamente , que também podem fornecer mais funções.

O comando de impressão

O comando de impressão é usado para produzir texto. O texto de saída sempre termina com uma string predefinida chamada separador de registro de saída (ORS), cujo valor padrão é uma nova linha. A forma mais simples desse comando é:

print
Isso exibe o conteúdo do registro atual. No AWK, os registros são divididos em campos e podem ser exibidos separadamente:
print $1
Mostra o primeiro campo do registro atual
print $1, $3
Exibe o primeiro e o terceiro campos do registro atual, separados por uma string predefinida chamada separador de campo de saída (OFS), cujo valor padrão é um único caractere de espaço

Embora esses campos ( $ X ) possam ter semelhanças com variáveis ​​(o símbolo $ indica variáveis ​​em Perl ), eles realmente se referem aos campos do registro atual. Um caso especial, $ 0 , refere-se a todo o registro. Na verdade, os comandos " print" e " print $0" são idênticos em funcionalidade.

O comando de impressão também pode exibir os resultados de cálculos e / ou chamadas de função:

/regex_pattern/ {
    # Actions to perform in the event the record (line) matches the above regex_pattern
    print 3+2
    print foobar(3)
    print foobar(variable)
    print sin(3-2)
}

A saída pode ser enviada para um arquivo:

/regex_pattern/ {
    # Actions to perform in the event the record (line) matches the above regex_pattern
    print "expression" > "file name"
}

ou através de um cano :

/regex_pattern/ {
    # Actions to perform in the event the record (line) matches the above regex_pattern
    print "expression" | "command"
}

Variáveis ​​integradas

As variáveis ​​integradas do awk incluem as variáveis ​​de campo: $ 1, $ 2, $ 3 e assim por diante ($ 0 representa o registro inteiro). Eles mantêm o texto ou valores nos campos de texto individuais em um registro.

Outras variáveis ​​incluem:

  • NR: Número de registros. Mantém uma contagem atual do número de registros de entrada lidos até agora de todos os arquivos de dados. Ele começa do zero, mas nunca é redefinido automaticamente para zero.
  • FNR: Número do arquivo de registros. Mantém uma contagem atual do número de registros de entrada lidos até agora no arquivo atual. Esta variável é redefinida automaticamente para zero cada vez que um novo arquivo é iniciado.
  • NF: Número de campos. Contém o número de campos no registro de entrada atual. O último campo no registro de entrada pode ser designado por $ NF, o segundo ao último campo por $ (NF-1), o terceiro ao último campo por $ (NF-2), etc.
  • FILENAME: Contém o nome do arquivo de entrada atual.
  • FS: Separador de campo. Contém o caractere "separador de campo" usado para dividir campos no registro de entrada. O padrão, "espaço em branco", inclui qualquer espaço e caracteres de tabulação. FS pode ser reatribuído a outro caractere para alterar o separador de campo.
  • RS: Separador de registro. Armazena o caractere "separador de registro" atual. Como, por padrão, uma linha de entrada é o registro de entrada, o caractere separador de registro padrão é uma "nova linha".
  • OFS: Separador de campo de saída. Armazena o "separador de campo de saída", que separa os campos quando o Awk os imprime. O padrão é um caractere de "espaço".
  • ORS: Separador de registro de saída. Armazena o "separador de registro de saída", que separa os registros de saída quando o Awk os imprime. O padrão é um caractere de "nova linha".
  • OFMT: Formato de saída. Armazena o formato para saída numérica. O formato padrão é "% .6g".

Variáveis ​​e sintaxe

Os nomes das variáveis ​​podem usar qualquer um dos caracteres [A-Za-z0-9_], com exceção das palavras-chave do idioma. Os operadores + - * / representam adição, subtração, multiplicação e divisão, respectivamente. Para concatenação de string , simplesmente coloque duas variáveis ​​(ou constantes de string) uma ao lado da outra. É opcional usar um espaço no meio se constantes de string estiverem envolvidas, mas dois nomes de variáveis ​​colocados adjacentes um ao outro requerem um espaço no meio. Aspas duplas delimitam constantes de string. As instruções não precisam terminar com ponto e vírgula. Finalmente, comentários podem ser adicionados a programas usando # como o primeiro caractere em uma linha.

Funções definidas pelo usuário

Em um formato semelhante ao C , as definições de função consistem na palavra-chave function, no nome da função, nos nomes dos argumentos e no corpo da função. Aqui está um exemplo de função.

function add_three (number) {
    return number + 3
}

Esta declaração pode ser invocada da seguinte forma:

(pattern)
{
   print add_three(36)     # Outputs '''39'''
}

As funções podem ter variáveis ​​que estão no escopo local. Os nomes deles são adicionados ao final da lista de argumentos, embora os valores deles devam ser omitidos ao chamar a função. É convenção adicionar alguns espaços em branco na lista de argumentos antes das variáveis ​​locais, para indicar onde os parâmetros terminam e as variáveis ​​locais começam.

Exemplos

Olá Mundo

Aqui está o programa habitual " Olá, mundo " escrito em AWK:

BEGIN { print "Hello, world!" }

Observe que uma exitdeclaração explícita não é necessária aqui; uma vez que o único padrão é BEGIN, nenhum argumento de linha de comando é processado.

Imprimir linhas com mais de 80 caracteres

Imprima todas as linhas com mais de 80 caracteres. Observe que a ação padrão é imprimir a linha atual.

length($0) > 80

Contar palavras

Conte as palavras na entrada e imprima o número de linhas, palavras e caracteres (como wc ):

{
    words += NF
    chars += length + 1 # add one to account for the newline character at the end of each record (line)
}
END { print NR, words, chars }

Como não há padrão para a primeira linha do programa, todas as linhas de entrada correspondem por padrão, então as ações de incremento são executadas para cada linha. Observe que words += NFé uma abreviação de words = words + NF.

Soma a última palavra

{ s += $NF }
END { print s + 0 }

s é incrementado pelo valor numérico de $ NF , que é a última palavra na linha conforme definido pelo separador de campo AWK (por padrão, espaço em branco). NF é o número de campos na linha atual, por exemplo, 4. Como $ 4 é o valor do quarto campo, $ NF é o valor do último campo na linha, independentemente de quantos campos esta linha tem, ou se tem mais ou menos campos do que as linhas adjacentes. $ é na verdade um operador unário com a maior precedência de operador . (Se a linha não tiver campos, então NF é 0, $ 0 é a linha inteira, que neste caso está vazia, exceto pelo possível espaço em branco e, portanto, tem o valor numérico 0.)

No final da entrada, o padrão END corresponde, então s é impresso. No entanto, como pode não haver nenhuma linha de entrada, caso em que nenhum valor foi atribuído a s , será, por padrão, uma string vazia. Adicionar zero a uma variável é uma expressão idiomática AWK para forçá-la de uma string a um valor numérico. (Concatenar uma string vazia é forçar de um número a uma string, por exemplo, s "" . Observe, não há operador para concatenar strings, elas são apenas colocadas adjacentes.) Com a coerção, o programa imprime "0" em uma entrada vazia , sem ele uma linha em branco é impressa.

Corresponde a um intervalo de linhas de entrada

NR % 4 == 1, NR % 4 == 3 { printf "%6d  %s\n", NR, $0 }

A instrução de ação imprime cada linha numerada. A função printf emula o printf C padrão e funciona de maneira semelhante ao comando print descrito acima. O padrão de correspondência, entretanto, funciona da seguinte maneira: NR é o número de registros, normalmente linhas de entrada, que AWK leu até agora, ou seja, o número da linha atual, começando em 1 para a primeira linha de entrada. % é o operador de módulo . NR% 4 == 1 é verdadeiro para a 1ª, 5ª, 9ª, etc., linhas de entrada. Da mesma forma, NR% 4 == 3 é verdadeiro para a 3ª, 7ª, 11ª, etc., linhas de entrada. O padrão de intervalo é falso até que a primeira parte corresponda, na linha 1, e então permanece verdadeiro até e inclusive quando a segunda parte corresponder, na linha 3. Ele então permanece falso até que a primeira parte corresponda novamente na linha 5.

Portanto, o programa imprime as linhas 1,2,3, pula a linha 4 e, a seguir, 5,6,7 e assim por diante. Para cada linha, ele imprime o número da linha (em um campo de 6 caracteres) e o conteúdo da linha. Por exemplo, quando executado nesta entrada:

Rome
Florence
Milan
Naples
Turin
Venice

O programa anterior imprime:

     1 Rome
     2 Florence
     3 Milan
     5 Turin
     6 Venice

Imprimir a parte inicial ou final de um arquivo

Como um caso especial, quando a primeira parte de um padrão de intervalo é constantemente verdadeira, por exemplo , 1 , o intervalo começará no início da entrada. Da mesma forma, se a segunda parte for constantemente falsa, por exemplo , 0 , a faixa continuará até o final da entrada. Por exemplo,

 /^--cut here--$/, 0

imprime linhas de entrada da primeira linha que corresponde à expressão regular ^ - corte aqui - $ , ou seja, uma linha contendo apenas a frase "- corte aqui--", até o final.

Calcular frequências de palavras

Frequência de palavras usando matrizes associativas :

BEGIN {
    FS="[^a-zA-Z]+"
}
{
    for (i=1; i<=NF; i++)
        words[tolower($i)]++
}
END {
    for (i in words)
        print i, words[i]
}

O bloco BEGIN define o separador de campo para qualquer sequência de caracteres não alfabéticos. Observe que os separadores podem ser expressões regulares. Depois disso, chegamos a uma ação simples, que executa a ação em todas as linhas de entrada. Nesse caso, para cada campo da linha, adicionamos um ao número de vezes que essa palavra, primeiro convertida em minúscula, aparece. Por fim, no bloco END, imprimimos as palavras com suas frequências. A linha

for (i in words)

cria um loop que atravessa as palavras do array , definindo i para cada subscrito do array. Isso é diferente da maioria das linguagens, em que esse loop passa por cada valor no array. O loop, portanto, imprime cada palavra seguida por sua contagem de frequência. tolowerfoi um acréscimo ao One True awk (veja abaixo) feito depois que o livro foi publicado.

Padrão de correspondência da linha de comando

Este programa pode ser representado de várias maneiras. O primeiro usa o shell Bourne para fazer um script de shell que faz tudo. É o mais curto desses métodos:

#!/bin/sh

pattern="$1"
shift
awk '/'"$pattern"'/ { print FILENAME ":" $0 }' "$@"

O $patternin no comando awk não é protegido por aspas simples para que o shell expanda a variável, mas precisa ser colocado entre aspas duplas para lidar corretamente com os padrões que contêm espaços. Um padrão por si só, da maneira usual, verifica se toda a linha ( $0) corresponde. FILENAMEcontém o nome do arquivo atual. awk não tem operador de concatenação explícito; duas strings adjacentes os concatenam. $0expande-se para a linha de entrada original inalterada.

Existem maneiras alternativas de escrever isso. Este script de shell acessa o ambiente diretamente de dentro do awk:

#!/bin/sh

export pattern="$1"
shift
awk '$0 ~ ENVIRON["pattern"] { print FILENAME ":" $0 }' "$@"

Este é um script de shell que usa ENVIRONum array introduzido em uma versão mais recente do One True awk após a publicação do livro. O subscrito de ENVIRONé o nome de uma variável de ambiente; seu resultado é o valor da variável. É como a função getenv em várias bibliotecas padrão e POSIX . O script de shell cria uma variável de ambiente patterncontendo o primeiro argumento, então elimina esse argumento e faz um awk procurar o padrão em cada arquivo.

~verifica se o operando esquerdo corresponde ao operando direito; !~é o seu inverso. Observe que uma expressão regular é apenas uma string e pode ser armazenada em variáveis.

A próxima maneira usa atribuição de variável de linha de comando, na qual um argumento para awk pode ser visto como uma atribuição para uma variável:

#!/bin/sh

pattern="$1"
shift
awk '$0 ~ pattern { print FILENAME ":" $0 }' "pattern=$pattern" "$@"

Ou você pode usar a opção de linha de comando -v var = value (por exemplo, awk -v pattern = "$ pattern" ... ).

Finalmente, isso é escrito em awk puro, sem a ajuda de um shell ou sem a necessidade de saber muito sobre a implementação do script awk (como a atribuição de variável na linha de comando faz), mas é um pouco demorado:

BEGIN {
    pattern = ARGV[1]
    for (i = 1; i < ARGC; i++) # remove first argument
        ARGV[i] = ARGV[i + 1]
    ARGC--
    if (ARGC == 1) { # the pattern was the only thing, so force read from standard input (used by book)
        ARGC = 2
        ARGV[1] = "-"
    }
}
$0 ~ pattern { print FILENAME ":" $0 }

O BEGINé necessário não apenas para extrair o primeiro argumento, mas também para evitar que seja interpretado como um nome de arquivo após o término do BEGINbloco. ARGC, o número de argumentos é sempre garantido como ≥1, como ARGV[0]é o nome do comando que executou o script, na maioria das vezes a string "awk". Observe também que ARGV[ARGC]é a string vazia "",. #inicia um comentário que se expande até o final da linha.

Observe o ifbloqueio. awk apenas verifica se deve ler a entrada padrão antes de executar o comando. Isso significa que

awk 'prog'

só funciona porque o fato de não haver nomes de arquivos só é verificado antes de progser executado! Se você definir explicitamente ARGCcomo 1 para que não haja argumentos, o awk simplesmente será encerrado porque parece que não há mais arquivos de entrada. Portanto, você precisa dizer explicitamente para ler a entrada padrão com o nome de arquivo especial -.

Scripts AWK independentes

Em sistemas operacionais do tipo Unix, scripts AWK autocontidos podem ser construídos usando a sintaxe shebang .

Por exemplo, um script que imprime o conteúdo de um determinado arquivo pode ser construído criando um arquivo denominado print.awkcom o seguinte conteúdo:

#!/usr/bin/awk -f
{ print $0 }

Pode ser invocado com: ./print.awk <filename>

O -finforma ao AWK que o argumento a seguir é o arquivo de onde ler o programa AWK, que é o mesmo sinalizador usado no sed. Uma vez que são freqüentemente usados ​​para uma linha, esses dois programas executam por padrão um programa fornecido como um argumento de linha de comando, em vez de um arquivo separado.

Versões e implementações

AWK foi originalmente escrito em 1977 e distribuído com a versão 7 do Unix .

Em 1985, seus autores começaram a expandir a linguagem, mais significativamente, adicionando funções definidas pelo usuário. O idioma é descrito no livro do AWK Linguagem de programação , publicado 1988 e sua implementação foi disponibilizado em versões do UNIX System V . Para evitar confusão com a versão anterior incompatível, essa versão às vezes era chamada de "novo awk" ou nawk . Esta implementação foi lançada sob uma licença de software livre em 1996 e ainda é mantida por Brian Kernighan (veja os links externos abaixo).

Versões antigas do Unix, como UNIX / 32V , incluídas awkcc, que convertiam AWK em C. Kernighan escreveu um programa para transformar awk em C ++; seu estado não é conhecido.

  • BWK awk , também conhecido como nawk , refere-se à versão de Brian Kernighan . Foi apelidado de "One True AWK" devido ao uso do termo em associação com o livro que originalmente descreveu o idioma e o fato de que Kernighan foi um dos autores originais de AWK. O FreeBSD se refere a esta versão como one-true-awk . Esta versão também possui recursos que não estão no livro, como tolowere ENVIRONque são explicados acima; consulte o arquivo FIXES no arquivo de origem para obter detalhes. Esta versão é usada, por exemplo, por Android , FreeBSD , NetBSD , OpenBSD , macOS e Illumos . Brian Kernighan e Arnold Robbins são os principais contribuidores para um repositório de código-fonte para nawk : github .com / onetrueawk / awk .
  • gawk ( GNU awk) é outra implementação de software livre e a única implementação que faz grandes progressos na implementação de internacionalização e localização e rede TCP / IP. Ele foi escrito antes que a implementação original se tornasse disponível gratuitamente. Inclui seu próprio depurador e seu criador de perfil permite que o usuário faça melhorias de desempenho medidas em um script. Ele também permite ao usuário estender a funcionalidade com bibliotecas compartilhadas. Algumas distribuições Linux incluem gawk como sua implementação AWK padrão.
    • gawk-csv . A extensão CSV do gawk fornece recursos para lidar com dados formatados em CSV de entrada e saída.
  • mawk é uma implementação AWK muito rápida de Mike Brennan baseada em um interpretador de bytecode .
  • libmawk é um fork do mawk, permitindo que aplicativos incorporem múltiplas instâncias paralelas de interpretadores awk.
  • awka (cujo front end é escrito sobre o programa mawk ) é outro tradutor de scripts AWK em código C. Quando compilados, incluindo estaticamente o libawka.a do autor, os executáveis ​​resultantes são consideravelmente acelerados e, de acordo com os testes do autor, se comparam muito bem com outras versões de AWK, Perl ou Tcl . Scripts pequenos se transformarão em programas de 160–170 kB.
  • tawk (Thompson AWK) é um compilador AWK para Solaris , DOS , OS / 2 e Windows , anteriormente vendido pela Thompson Automation Software (que encerrou suas atividades).
  • Jawk é um projeto de implementação de AWK em Java , hospedado no SourceForge. Extensões à linguagem são adicionadas para fornecer acesso aos recursos Java em scripts AWK (ou seja, threads Java, soquetes, coleções, etc.).
  • xgawk é um fork do gawk que estende o gawk com bibliotecas carregáveis ​​dinamicamente. A extensão XMLgawk foi integrada ao GNU Awk oficial versão 4.1.0.
  • QSEAWK é uma implementação de interpretador AWK embutido incluída na biblioteca QSE que fornece interface de programação de aplicativo (API) embutida para C e C ++ .
  • libfawk é um interpretador muito pequeno, somente função, reentrante e incorporável escrito em C
  • BusyBox inclui uma implementação AWK escrita por Dmitry Zakharov. Esta é uma implementação muito pequena adequada para sistemas embarcados.
  • CLAWK de Michael Parker fornece uma implementação AWK em Common Lisp , baseada na biblioteca de expressões regulares do mesmo autor.

Livros

  • Aho, Alfred V .; Kernighan, Brian W .; Weinberger, Peter J. (01/01/1988). A linguagem de programação AWK . New York, NY: Addison-Wesley . ISBN 0-201-07981-X. Recuperado em 22/01/2017 .
  • Robbins, Arnold (15/05/2001). Programação eficaz de awk (3ª ed.). Sebastopol, CA: O'Reilly Media . ISBN 0-596-00070-7. Página visitada em 16-04-2009 .
  • Dougherty, Dale ; Robbins, Arnold (01/03/1997). sed e awk (2ª ed.). Sebastopol, CA: O'Reilly Media. ISBN 1-56592-225-5. Página visitada em 16-04-2009 .
  • Robbins, Arnold (2000). Programação efetiva do Awk: Um Guia do Usuário para Gnu Awk (1.0.3 ed.). Bloomington, IN: iUniverse . ISBN 0-595-10034-1. Arquivado do original em 12 de abril de 2009 . Página visitada em 2009-04-16 .

Veja também

Referências

Leitura adicional

links externos