summaryrefslogtreecommitdiffhomepage
path: root/pt-br/awk-pt.html.markdown
blob: d54081a386e572c7a468cc30ed279e455e52d843 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
---
category: tool
tool: awk
filename: learnawk-pt.awk
contributors:
    - ["Marshall Mason", "http://github.com/marshallmason"]
translators:
    - ["Paulo Henrique Rodrigues Pinheiro", "https://github.com/paulohrpinheiro"]
lang: pt-br

---

AWK é uma ferramenta padrão em todos os sistemas UNIX compatíveis com POSIX. É
como um Perl despojado, perfeito para tarefas de processamento de texto e
outras tarefas de script.  Possui uma sintaxe C-like, mas sem ponto e vírgula,
gerenciamento manual de memória, ou tipagem estática. Destaca-se no
processamento de texto. Você pode chamá-lo a partir de um shell-script, ou você
pode usá-lo como uma linguagem de script autônomo.

Por que usar AWK ao invés de Perl? Principalmente porque AWK faz parte do UNIX.
Você pode sempre contar com ele, enquanto o futuro do Perl é indefinido. AWK é
também mais fácil de ler que Perl. Para scripts simples de processamento de
texto, particularmente aqueles que leem arquivos linha por linha e fatiam texto
por delimitadores, AWK é provavelmente a ferramenta certa para a tarefa.

```awk
#!/usr/bin/awk -f

# Comentários são assim

# Programas AWK consistem de uma coleção de padrões e ações. O mais
# importante padrão é chamado BEGIN. Ações estão dentro de blocos
# entre chaves.

BEGIN {

    # O bloco BEGIN será executado no começo do programa. É onde você coloca
    # todo código que prepara a execução, antes que você processe qualquer
    # arquivo de texto. Se você não tem arquivos de texto, então pense no
    # BEGIN como o ponto principal de entrada.

    # Variáveis são globais. Simplesmente atribua valores ou as use, sem
    # necessidade de declarar.

    # Operadores são como em C e similares
    a = count + 1
    b = count - 1
    c = count * 1
    d = count / 1 # divisão inteira
    e = count % 1 # módulo
    f = count ^ 1 # exponenciação

    a += 1
    b -= 1
    c *= 1
    d /= 1
    e %= 1
    f ^= 1

    # Incrementando e decrementando por um
    a++
    b--

    # Como um operador pré-fixado, retorna o valor incrementado
    ++a
    --b

    # Perceba, não há pontuação, como ponto-e-vírgula, ao final das declarações

    # Declarações de controle
    if (count == 0)
        print "Começando com count em 0"
    else
        print "Como é que é?"

    # Ou você pode usar o operador ternário
    print (count == 0) ? "Começando com count em 0" : "Como é que é?"

    # Blocos multilinhas devem usar chaves
    while (a < 10) {
        print "Concatenação de texto é feita" " com uma série" " de"
            " textos separados por espaço"
        print a

        a++
    }

    for (i = 0; i < 10; i++)
        print "Uma boa opção para um loop de uma linha"

    # Quanto a comparações, eis os padrões:
    a < b   # Menor que
    a <= b  # Menor ou igual a
    a != b  # Não igual
    a == b  # Igual
    a > b   # Maior que
    a >= b  # Maior ou igual a

    # Bem como operadores lógicos
    a && b  # E
    a || b  # OU (inclusivo)

    # Em adição, há o utilíssimo operador para expressões regulares
    if ("foo" ~ "^fo+$")
        print "Fooey!"
    if ("boo" !~ "^fo+$")
        print "Boo!"

    # Matrizes
    arr[0] = "foo"
    arr[1] = "bar"
    # Infelizmente, não há outra forma para inicializar uma matriz. Apenas
    # coloque cada valor em uma linha, como mostrado acima.

    # Você também pode ter matrizes associativas
    assoc["foo"] = "bar"
    assoc["bar"] = "baz"

    # E matrizes multidimensionais, com algumas limitações que não mencionarei
    multidim[0,0] = "foo"
    multidim[0,1] = "bar"
    multidim[1,0] = "baz"
    multidim[1,1] = "boo"

    # Você pode testar a pertinência de um elemento em uma matriz
    if ("foo" in assoc)
        print "Fooey!"

    # Você pode também usar o operador 'in' para percorrer as chaves de uma
    # matriz associativa
    for (key in assoc)
        print assoc[key]

    # Os argumentos da linha de comando estão em uma matriz especial ARGV
    for (argnum in ARGV)
        print ARGV[argnum]

    # Você pode remover elementos de uma matriz
    # Isso é muito útil para prevenir que o AWK assuma que os argumentos são
    # arquivo para ele processar
    delete ARGV[1]

    # A quantidade de argumentos passados está na variável ARGC
    print ARGC

    # O AWK tem várias funções nativas. Elas estão separadas em três categorias.
    # Demonstrarei cada uma delas logo mais abaixo.

    return_value = arithmetic_functions(a, b, c)
    string_functions()
    io_functions()
}

# Eis como você deve definir uma função
function arithmetic_functions(a, b, c,    d) {

    # Provavelmente a parte mais irritante do AWK é ele não possuir variáveis
    # locais. Tudo é global. Para pequenos scripts, isso não é problema, e
    # pode até mesmo ser considerado útil, mas para grandes scripts, isso pode
    # ser um problema.

    # Mas há como contornar isso (um hack). Os argumentos de função são locais
    # para a função e o AWK permite que você defina mais argumentos de função
    # do que ele precise. Então, coloque a variável local na declaração de
    # função, como eu fiz acima. Como uma convenção, adicione alguns espaços
    # extras para distinguir entre parâmetros de função reais e variáveis
    # locais. Neste exemplo, a, b e c são parâmetros reais, enquanto d é
    # meramente uma variável local.

    # Agora, serão demonstradas as funções aritméticas

    # Muitas implementações AWK possuem algumas funções trigonométricas padrão
    localvar = sin(a)
    localvar = cos(a)
    localvar = atan2(b, a) # arco-tangente de b / a

    # E conteúdo logarítmico
    localvar = exp(a)
    localvar = log(a)

    # Raiz quadrada
    localvar = sqrt(a)

    # Descartando a parte não inteira de um número em ponto flutuante.
    localvar = int(5.34) # localvar => 5

    # Números aleatórios
    srand() # Forneça uma semente como argumento. Por padrão, ele usa a hora atual
    localvar = rand() # Número aleatório entre 0 e 1.

    # Aqui mostramos como retornar um valor
    return localvar
}

function string_functions(    localvar, arr) {

    # Sendo o AWK uma linguagem para processamento de texto, ele possui
    # várias funções para manipulação de texto, muitas das quais
    # fortemente dependentes de expressões regulares.

    # Procurar e substituir, primeira instância (sub), ou todas (gsub)
    # Ambas retornam o número de instâncias substituídas
    localvar = "fooooobar"
    sub("fo+", "Meet me at the ", localvar) # localvar => "Meet me at the bar"
    gsub("e", ".", localvar) # localvar => "M..t m. at th. bar"

    # Localiza um texto que casa com uma expressão regular
    # index() faz a mesma coisa, mas não permite uma expressão regular
    match(localvar, "t") # => 4, pois 't' é o quarto carácter

    # Separa por delimitador
    split("foo-bar-baz", arr, "-") # a => ["foo", "bar", "baz"]

    # Outras coisas úteis
    sprintf("%s %d %d %d", "Testing", 1, 2, 3) # => "Testing 1 2 3"
    substr("foobar", 2, 3) # => "oob"
    substr("foobar", 4) # => "bar"
    length("foo") # => 3
    tolower("FOO") # => "foo"
    toupper("foo") # => "FOO"
}

function io_functions(    localvar) {

    # Você já viu como imprimir
    print "Hello world"

    # Também há o printf
    printf("%s %d %d %d\n", "Testing", 1, 2, 3)

    # O AWK não disponibiliza manipuladores de arquivo. Ele irá automaticamente
    # manipular um arquivo quando você fizer algo que precise disso. O texto
    # que você usou para isso pode ser usado como um manipulador de arquivo,
    # para propósitos de E/S. Isso faz ele parecer com um shell script:

    print "foobar" >"/tmp/foobar.txt"

    # Agora a string "/tmp/foobar.txt" é um manipulador de arquivos. Você pode
    # fechá-lo:
    close("/tmp/foobar.txt")

    # Aqui está como você pode executar alguma coisa no shell
    system("echo foobar") # => prints foobar

    # Lê uma linha da entrada padrão e armazena em localvar
    getline localvar

    # Lê uma linha de um pipe
    "echo foobar" | getline localvar # localvar => "foobar"
    close("echo foobar")

    # Lê uma linha de um arquivo e armazena em localvar
    getline localvar <"/tmp/foobar.txt"
    close("/tmp/foobar.txt")
}

# Como dito no início, os programas AWK consistem de uma coleção de padrões
# e ações. Você já viu o padrão BEGIN, o mais importante. Outros padrões são
# usados apenas se você estiver processando linhas de arquivos ou a entrada
# padrão.

# Quando você passa argumentos para o AWK, eles são tratados como nomes de
# arquivos para processar. Todos serão processados, em ordem. Pense nisso como
# um implícito para loop, iterando sobre as linhas nesses arquivos. Esses
# padrões e ações são como instruções de mudança dentro do loop.

/^fo+bar$/ {

    # Esta ação será executada para cada linha que corresponda à expressão
    # regular, / ^ fo + bar $ /, e será ignorada para qualquer linha que não
    # corresponda. Vamos apenas imprimir a linha:

    print

    # Opa, sem argumento! Isso ocorre pois print tem um argumento padrão: $0.
    # $0 é o nome da linha atual que está sendo processada. Essa variável é
    # criada automaticamente para você.

    # Você provavelmente pode adivinhar que existem outras variáveis $. Toda
    # linha é implicitamente dividida antes de cada ação ser chamada, como
    # o shell faz. E, como o shell, cada campo pode ser acessado com um sinal
    # de cifrão

    # Isso irá imprimir o segundo e quarto campos da linha
    print $2, $4

    # O AWK automaticamente define muitas outras variáveis para ajudar você
    # a inspecionar processar cada linha. A mais importante delas é NF.

    # Imprime o número de campos da linha atual
    print NF

    # Imprime o último campo da linha atual
    print $NF
}

# Todo padrão é na verdade um teste verdadeiro/falso. A expressão regular no
# último padrão também é um teste verdadeiro/falso, mas parte dele estava
# escondido. Se você não informar um texto para testar, AWK assumirá $0,
# a linha que está atualmente sendo processada. Assim, a versão completa
# é a seguinte:

$0 ~ /^fo+bar$/ {
    print "Equivalente ao último padrão"
}

a > 0 {
    # Isso será executado uma vez para cada linha, quando a for positivo
}

# Você entendeu. Processar arquivos de texto, ler uma linha de cada vez, e
# fazer algo com ela, particularmente dividir com base em um delimitador, é
# tão comum no UNIX que AWK é uma linguagem de script que faz tudo por você,
# sem você precisa perguntar. Tudo o que você precisa fazer é escrever os
# padrões e ações com base no que você espera da entrada, e o que você quer
# fazer com isso.

# Aqui está um exemplo rápido de um script simples, o tipo de coisa que o AWK
# é perfeito para fazer. Ele irá ler um nome da entrada padrão e depois
# imprimirá a média de idade de todos com esse primeiro nome. Digamos que você
# forneça como argumento o nome de um arquivo com esses dados:

# Bob Jones 32
# Jane Doe 22
# Steve Stevens 83
# Bob Smith 29
# Bob Barker 72
#
# Eis o script:

BEGIN {

    # Primeiro, pergunte o nome do usuário
    print "Para qual nome você quer calcular a média de idade?"

    # Pega uma linha da entrada padrão, não dos arquivos indicados na
    # linha de comando
    getline name <"/dev/stdin"
}

# Agora, processa cada linha em que o primeiro nome é o nome informado
$1 == name {

    # Dentro desse bloco, nós temos acesso a algumas variáveis uteis, que
    # foram pré-carregadas para nós:
    # $0  é a linha corrente completa
    # $3 é o terceiro campo, que é o que nos interessa aqui
    # NF é a quantidade de campos, que deve ser 3
    # NR é o número de registros (linhas) lidas até agora
    # FILENAME é o nome do arquivo sendo processado
    # FS é o delimitador em uso, que é " " aqui
    # ...etc. Há muito mais, documentadas no manual.

    # Mantenha um registro do total e da quantidade de linhas encontradas
    sum += $3
    nlines++
}

# Outro padrão especial é chamado END. Ele será executado após o processamento
# de todos os arquivos de texto. Ao contrário de BEGIN, ele só será executado
# se você tiver dado a ele dados para processar. Ele será executado depois de
# todos os arquivos terem sido lidos e processados de acordo com as regras e
# ações que você forneceu. O objetivo disso em geral é produzir algum tipo de
# relatório final, ou fazer algo com o agregado dos dados acumulados ao longo
# do script.

END {
    if (nlines)
        print "A média da idade para " name " é " sum / nlines
}
```

Leituras adicionais (em inglês):

* [Awk tutorial](http://www.grymoire.com/Unix/Awk.html)
* [Awk man page](https://linux.die.net/man/1/awk)
* [The GNU Awk User's Guide](https://www.gnu.org/software/gawk/manual/gawk.html)
  GNU AWK é encontrado na maioria dos sistemas GNU/Linux.