Jer 14
Jer 14
SHELL E BASH
Curitiba PR
2018
Este trabalho está licenciado segundo a licença Creative Commons Atribuição-NãoComercial-
SemDerivações 4.0 Internacional (CC BY-NC-ND 4.0). Para ver uma cópia dessa licenca, visite
https://creativecommons.org/licenses/by-nc-nd/4.0/deed.pt_BR
Resumo
1 Introdução . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.1 História do UNIX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
1.2 História da Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
1.3 BASH e terminal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7
2 Arquivos, Coringas e Redirecionamento . . . . . . . . . . . . . . . . . . . . . 8
2.1 Coringas e Expansões . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
2.2 Entrada/Saída e Pipelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
2.3 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3 Customização do Ambiente . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.1 Arquivos especiais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.2 Aliases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.3 Opções da Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.4 Variáveis da Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
3.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
4 Navegação sem o uso do Mouse . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.1 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
5 Controle de Processos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5.1 Controle de Jobs e Signals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
5.2 Co-rotinas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
5.3 Sub-shells . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
5.4 Substituição de Processos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
5.5 Exercícios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
6 Exemplo Práticos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
6.1 Problema 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
6.2 Solução problema 6.1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
6.3 Problema 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
6.4 Solução problema 6.3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
6.5 Problema 3 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
6.6 Solução problema 6.5 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
7 Conclusão . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Referências . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5
1 Introdução
linhas de comando chamadas pipelines. Então um ano depois, o sistema UNIX era re-escrito em
uma linguagem de mais alto nível, a linguagem C, para que obtivesse portabilidade para outras
plataformas computacionais. Sendo assim, sua quinta versão era lançada e licenciada para fins
educacionais e em 1975, era licenciada sua sexta versão para outras empresas e companhias [10],
com uma nova versão da sua shell.
E além da portabilidade de plataforma, também era necessário que o sistema se tornasse
independente de máquina. Para isso, os pesquisadores dos laboratórios da AT&T (Bell Labs)
desenvolveram uma versão para uma máquina chamada Interdata 8/32 em 1977. Sendo em 1979
lançada a Versão 7 UNIX, provendo aproximadamente 50 system calls e também a primeira
versão popular da shell: a Bourne Shell, que concorria com a C-Shell na área acadêmica.
No começo dos anos 80, várias versões foram desenvolvidas pela empresa Bell e com
isso o interesse de estudantes e profissionais cientistas da computação aumentou, fazendo com que
o UNIX fosse visto como um potencial sistema operacional adequado para todos os computadores.
Assim, em 1983, o UNIX kernel era composto de código majoritariamente escrito em C, com
mais de 75% independente de máquina e chamado UNIX System V Release 1 [7]. Nesse mesmo
ano, o projeto de software livre GNU, foi fundado.
Devido ao fato de existirem muitas implementações ao mesmo tempo, a empresa AT&T
criou e emitiu um padrão em 1985, o System V Interface Definition (SVID), exigindo que os
sistemas operacionais fossem marcados como "System V"como conformidade. Ademais, em
1988, a empresa tomou mais um passo na padronização e fez parcerias com outras empresas do
mercado. A principal, foi buscar colaboração com a Sun Microsystems e juntar esforços para o
que viria a se tornar o System V Release 4 [7].
Por volta de 1991, o UNIX vinha ganhando concorrência do Linux kernel, que utilizava
partes do projeto GNU e era uma reimplementação do UNIX. Trazendo consigo uma nova versão
para o interpretador de linha de comando, a Bourne-Again Shell (Bash), e sendo chamado de
"GNU/Linux". De modo que, a partir disso foram sendo lançadas versões e distribuições do
GNU/Linux [8], que por muitos é chamado apenas de Linux, contribuindo para que fosse o
sistema operacional baseado em UNIX mais utilizado até hoje. Com base nisso, este trabalho
pretende abordar múltiplas questões relacionadas a uma das componentes desse sistema, a shell.
de scripts. Na mesma época, a C-shell era desenvolvida por um grupo de pesquisa da universidade
da Califórnia, no Estados Unidos da América, com o objetivo de possuir scripts similares aos da
linguagem C. Além disso, também possibilitava a visualizção do histórico dos comandos [3].
Ainda por volta da metade da década de 70 até 1980, surgia a Korn shell, que também
podia ser usada como linguagem de script. Ela era compatível com versões anteriores do
Bourne shell original, que passou a ser pouco utilizada quando a Bourne-Again shell foi criada
em 1988. Popularmente chamada Bash, é um dos interpretadores mais utilizado em sistemas
baseados em UNIX. Sendo assim, será utilizada como referência para explicação de comandos,
funcionalidades e resultados de comandos neste trabalho.
• Arquivos regulares: contém caracteres legíveis para um humano e também podem ser
chamados de arquivos-texto.
Esses arquivos são armazenados em diretórios que, além dos arquivos, podem conter
sub-diretórios. Sendo assim, cria-se uma estrutura hierárquica conhecida como árvore, onde o
diretório mais acima é a raiz. Dessa forma, todo arquivo pode ter nomeada sua localização no
sistema em relação a raiz ao listar todos os diretórios (em ordem, a partir da raiz) separados por
barras (/ ), seguido do nome do arquivo. Essa nomeação é chamada de caminho absoluto. Dessa
forma, o acesso e manipulação desses arquivos e diretórios pode ocorrer via terminal.
O comando mais utilizado para listagem de nomes de arquivos e diretórios contidos no
diretório corrente, é o ls, o qual possui opções que mostram mais informações. Por exemplo,
ls -l, que devolve permissões, proprietário, grupo, tamanho e data/hora modificada, e -ha, que
devolve o tamanho de forma legível para um humano e inclui entradas começadas com . (ponto).
Além disso, listagens ordenadas por tamanho e por data/hora de modificação podem ser obtidas
com a opção -S, na qual o maior aparece primeiro, e com -t, com o mais recente primeiro,
respectivamente.
Arquivos e diretórios vazios podem ser criados com as linhas de comando touch
nome_do_arquivo.txt ou > nome_do_arquivo.txt (o símbolo > será explicado mais para
frente), e mkdir nome_do_diretório, respectivamente. Vale ressaltar que o touch cria um
arquivo vazio apenas se ele não existir e caso contrário, apenas atualiza sua data de modificação.
Indo além, a opção -p permite que seja verificada a existência de um diretório antes de criá-lo,
podendo ser acessado com cd. A verificação do nome do diretório corrente é dada por pwd.
Já a cópia de arquivos é feita utilizando cp, que deve receber como argumento a origem
e o destino. Para diretórios, esse comando deve ser utilizado com a opção -R uma vez que
9
pode conter arquivos e sub-diretórios [2]. De forma análoga, o comando mv é utilizado para
mover arquivos e diretórios, mas também para renomeá-los. E da mesma maneira que arquivos e
diretórios podem ser criados, eles podem ser removidos, sendo o comando rm utilizado para
arquivos e a opção -r para a remoção recursiva de algum diretório [2].
A exibição de arquivos pode ocorrer com o comando cat, que mostra o tanto de caracteres
que pode-se observar na tela. Mas caso o arquivo seja maior que essa quantidade máxima, basta
ir pressionando enter até o final do documento com o comando more, b para voltar uma ou mais
páginas e q para sair (quit). Além dos comandos head e tail, usados para visualizar apenas as dez
primeiras e últimas linhas do arquivo, respectivamente. Ademais, também permitem estipular
outras quantidades de linhas com a opção -n e a quantidade de bytes com a opção -c [9].
Além disso, arquivos e diretórios também podem ser procurados a partir do comando
find. Ele possui várias opções que permitem a busca de arquivos, que normalmente são buscados
com a opção -iname, sendo que a string após a opção deve casar com nome do arquivo e ainda, o
i significa que pode ser tanto minúsculo quanto maiúsculo. Ou então para procurar arquivos que
contém números, deve-se acrescentar o número desejado após o -inum [2].
Coringa Substituição
? qualquer caracter único
* qualquer sequência de caracteres
[conjunto] qualquer caracter dentro do conjunto
[!conjunto] qualquer caracter fora do conjunto
{termo} parte do nome por termo
Por exemplo, digamos que no diretório corrente existam os arquivos bst.c, bst.log, bst.o
e bst.h, então o comando ls bst.? irá devolver todos os arquivos, excluindo bst.log. Já o
comando ls bst.* devolve todos [11]. Assim, para melhor entendimento do coringa presente
no último comando, a Tabela 2.2 demonstra alguns exemplos de seu funcionamento. Considere
os arquivos alice, clarice, daniel, joice e lucas, presentes no diretório de trabalho.
10
Expressão Substituição
*e alice, clarice, joice
*l* alice, clarice, daniel, lucas
l* lucas
* alice, clarice, daniel, joice, lucas
deles executa um tipo específico de filtragem no texto de entrada, sendo essenciais para o uso
produtivo do shell. Os mais utilizados podem ser vistos na Tabela 2.3.
Utilitário Fim
cat imprime a entrada na saída padrão; concatena arquivos
grep procura por strings na entrada
sort ordena as linhas da entrada
cut extrai colunas da entrada
2.3 Exercícios
Tendo isso em vista, a seguir são propostos três exercícios referentes aos assuntos
discutidos neste capítulo. Cada um dos comando citados, referenciados ou exemplificados, possui
uma página do bash com todas as opções utilizáveis, códigos de saída, expressões regulares,
descrição, entre outros, que pode ser acessada digitando man comando . (Todos comandos do
bash possuem essa man page.)
1. Crie o diretório teste e dentro dele crie três arquivos texto vazios: sinonimo, tradutor e
funcao.
12
Resposta:
mkdir teste
cd teste
touch sinonimo.txt
touch tradutor.txt
touch funcao.txt
2. Liste todos os arquivos texto presentes no diretório corrente que comecem com letra
minúscula e não contenham dígitos no segundo caracter do nome.
Resposta:
ls [a-z][!0-9]*.txt
3 Customização do Ambiente
3.2 Aliases
Muitas vezes os comandos mais utilizados são os que são usados com uma string de
opções e argumentos que precisam ser especificados. Para que seja mais fácil invocá-los, existe
uma ferramenta bash que permite renomear esses comandos chamada alias. Aliases podem
14
ser definidos em uma linha de comando nos aquivos .bash_profile ou .bashrc, com a forma
alias nome=comando. Assim, toda vez que nome é digitado como comando, a bash executará
o comando definido após o igual (=).
Um dos usos mais básicos para um alias, é utilizar nomes mais mnemônicos para
determinados comandos. Por exemplo, o comando grep: uma utilidade de busca cujo nome
surgiu de Generalized Regular Expression Parser e que pode ser trivial para um cientista da
computação, mas não para um administrador de escritório, que usaria o alias alias search=grep
com mais facilidade. Outro uso básico de aliases, são para erros tipográficos na hora de invocar
alguns comandos.
Além disso, comandos possuem opções que devem ser escritas maiúsculas e pode ser
inconveniente digitar - seguido de uma letra maiúscula. Por exemplo o comando ls, que possui
a opção -F para mostrar uma barra (/) após cada diretório e um asterisco (*) após executáveis.
Dessa forma, alias lf=’ls -F’, é um alias largamente usado [11].
Porém, alguns pontos sobre aliases devem ser lembrados. Primeiro, que a bash faz uma
substituição textual, de forma que o comando é repassado a um processador de texto antes de ser
interpretado e executado. Sendo assim, caracteres especias, como coringas, são interpretados
de forma correta. Segundo, um alias é recursivo, de modo que é possível criar um alias para
um alias, mas não um loop infinito. Por exemplo, alias pa=printall é um alias para alias
printall=’pr * | lpr’.
Outra ferramenta com uma finalidade parecida é o shopt, que substitui as configurações
de opções através de set e variáveis de ambiente. A funcionalidade shopt -o é uma duplicação de
15
partes do comando set. Sendo usado da forma shopt opções nomeopção , onde a opção -p
lista cada opção e seu valor corrente. Além disso, as opções -s e -u sem nomeopção retornam
as opções habilitadas e desabilitadas, respectivamente [5]. Algumas de suas opções (como de
comandos) são vistas na tabela 3.2.
Opção Descrição
-s Habilita (set) toda nomeopção
-u Desabilita (unset) toda nomeopção
Suprime a saída padrão, o retorno é se
nomeopção esta habilitada ou não
-q
(zero se todas estão habilitadas,
diferente de zero caso contrário)
Permite que o valor de nomeopção
-o
seja igual ao do comando set -o
3.5 Exercícios
Isto posto, a seguir são propostos três exercícios referentes aos assuntos discutidos neste
capítulo. Cada um dos comando citados, referenciados ou exemplificados, possui uma página do
bash com todas as opções utilizáveis, códigos de saída, expressões regulares, descrição, entre
outros, que pode ser acessada digitando man comando . (Todos comandos do bash possuem essa
man page.)
cd. Atenção: crie os aliases apenas na shell corrente, ou se criar em algum dos arquivos
especiais, remova-os depois.
Resposta:
mkdir -p ci320/relatorios/trabalho4
alias dir=’ci320/relatorios/trabalho4’
alias cd=’cd ’
cd dir
2. Faça com que pequenos erros de digitação no nome do diretório para o qual você deseja
fazer um cd serão ignorados. Por exemplo, faça o comando ’cd Docments’ entrar no
diretório ’Documentos’. Dica: use alguma das opções da shell com o comando shopt.
Resposta:
shopt -s cdspell
3. Crie uma variável chamada ’chuva’ e atribua o valor ’Dias de chuva necessitam de mais
espaços entre as palavras.’ (com quatro espaços entre duas quaisquer palavras da frase).
Depois imprima a variável exatamente como atribuído.
Resposta:
chuva="Dias de chuva necessitam de mais espaços entre as"palavras.
echo "$chuva"
17
Vários comandos que foram explicados e exemplificados neste trabalho (até aqui) são
úteis para manipular (remoção, edição, renomeação, cópia, etc) a hierarquia de diretórios e
arquivos utilizando apenas o terminal e seus comandos via teclado. Como já mencionado, é
aberto com CTRL + ALT + T. Além disso, uma nova aba é aberta na mesma janela pressionando
CTRL + SHIFT + T. Sendo o acesso entre diferentes abas feito com ALT + n, onde n é o
número da aba, que por sua vez, pode ser fechada utilizando CTRL + SHIFT + W ou exit.
Existe uma variação do terminal chamada Terminator [6], que quando instalado é aberto
da mesma forma que seu terminal-pai. Nele, uma nova aba é aberta com o mesmo comando
no teclado, porém a alternação é feita com CTRL + pgdn ou CTRL + pgup. No entanto, o
terminator possui a funcionalidade de arranjar vários terminais (sub-shell) em grid, onde CTRL
+ SHIFT + E e CTRL + SHIFT + O dividem a aba corrente vertical e horizontalmente, podendo
ser fechadas da mesma forma que no terminal. Vale ressaltar que as novas abas e divisões
possuem o mesmo diretório corrente a partir de onde foram abertas.
Assim como é possível alternar entre abas/divisões, é possível alternar entre janelas
de terminal e janelas de outros aplicativos utilizando a combinação ALT + TAB. Essas janelas
também podem ser trocadas de área de trabalho, que podem ser chaveadas com CRTL + ALT +
setas, combinando CTRL + SHIFT + ALT. Além disso, também é viável aumentar ou diminuir
a fonte de uma janela/aba de terminator com CTRL + SHIFT + + e CTRL + -, respectivamente.
Vale ressaltar que esses atalhos de teclado funcionam em sistemas GNU/LINUX, inclusive se
comportam de forma muito semelhante quando lidando com dois monitores.
No entanto, ao utilizar comandos e linhas de comando em uma shell UNIX no terminal
ou no terminator, erros de sintaxe podem ser críticos. Uma vez que a sintaxe da shell é poderosa,
mas também concisa e cheia de caracteres especiais que podem ser utilizados de diferentes
formas, ela não é muito mnemônica e permite construções de linhas de comandos que são tão
obscuras quanto complexas [11]. Felizmente a linguagem bash possui um histórico de comandos
que possibilita a recuperação de linhas de comando e evita a reescrita das mesmas.
Além desse histórico, bash permite editar comandos e linhas de comandos com comandos
similares aos dos que pertencem aos dois editores mais populares do UNIX: vi e emacs. Dos
quais, o primeiro possui comandos geralmente compostos por letras sozinhas ou em duplas,
sendo elas maiúsculas e minúsculas, ou nas duas formas. Apenas em alguns casos são utilizados
caracteres especiais. Já o segundo modo, tem comandos que geralmente combinam as teclas
18
CTRL e ESC com alguma letra ou símbolo, sendo um modo de edição mais facilmente entendido
e usado.
4.1 Exercícios
Isto posto, a seguir são propostos três exercícios referentes aos assuntos discutidos neste
capítulo. Cada um dos comando citados, referenciados ou exemplificados, possui uma página do
bash com todas as opções utilizáveis, códigos de saída, expressões regulares, descrição, entre
outros, que pode ser acessada digitando man comando . (Todos comandos do bash possuem essa
man page.)
1. Leia o capítulo 2 do livro "Learning the bash shell: Unix shell programming", dos
autores Cameron Newham e Bill Rosenblatt [11].
2. Verifique qual é o modo de edição padrão da sua shell. Então habilite o outro modo de
edição e depois volte para o padrão. (Considere que a resposta tem como modo padrão
o emacs.)
Resposta:
set -o
set -o vi
tset -o emacs
3. Quais são os comandos de mover o cursor um caracter para frente e para trás dos modos
de edição emacs e vi, respectivamente?
Resposta:
emacs: CTRL + F e CTRL + B
vi: h e l
19
5 Controle de Processos
5.2 Co-rotinas
Controle de processos é realizado diretamente na shell (terminal), como já posto, mas
também dentro de programas shell. E quando dois ou mais deles executam ao mesmo tempo
com possibilidade de comunicação, são denominados co-rotinas. Essas co-rotinas nada mais
são que o recurso utilizado por pipelines, que por sua vez encapsulam uma série de regras sobre
como processos devem se comunicar.
Um exemplo seria o pipeline ls | more, no qual (1) são criados dois subprocessos, P1
e P2 (chamada ao sistema fork), (2) é configurada a entrada/saída entre os processos de modo
que a saída de P1 sirva como entrada para a entrada de P2 (pipe), (3) dá início ao ls (exec), (4) dá
início ao more (exec) e (5) aguarda o término dos processos (wait).
Mas caso não haja comunicação entre processos executados simultaneamente, o controle
é um pouco mais fácil. Por exemplo, se dento de um script há um comando executado em
background (utilizando &) e ele continuar rodando após o término do script em si, ele se torna
órfão e é preferível que isso não aconteça. Assim, para que isso seja evitado, utiliza-se o
comando wait sem argumentos, afim de esperar até que todos os processos em background
estejam terminados [11].
21
5.3 Sub-shells
Outro tipo de relação inter-processo, é a de uma sub-shell e sua shell-pai. Das duas, a
primeira herda da segunda (como já mencionado) o diretórios corrente, variáveis de ambiente, os
descritores de arquivos e sinais ignorados, além de uma parte das variáveis da shell e como são
tratados os demais sinais. Além disso, quando um script shell é executado ele cria uma sub-shell.
5.5 Exercícios
Isto posto, a seguir são propostos três exercícios referentes aos assuntos discutidos neste
capítulo. Cada um dos comando citados, referenciados ou exemplificados, possui uma página do
bash com todas as opções utilizáveis, códigos de saída, expressões regulares, descrição, entre
outros, que pode ser acessada digitando man comando . (Todos comandos do bash possuem essa
man page.)
1. Verifique quais processos estão rodando na shell corrente, com um comando que mostre
o PID, a TTY e o comando sendo executado.
Resposta:
ps
2. Escreva uma utilidade que permite fazer várias cópias de um mesmo arquivo de forma
paralela. Considere que o usuário não passe destinos de mesmo nome. (Leia a seção
8.5 do livro "Learning the bash shell: Unix shell programming", com autores Cameron
Newham e Bill Rosenblatt [11].)
Resposta:
22
1 # !/ bin / bash
2
3 file = $1
4 shift
5 for dest in " $@ " ; do
6 cp $file $dest &
7 done
8 wait
6 Exemplo Práticos
6.1 Problema 1
A descrição, código e local dos itens pertencentes ao patrimônio do DInf (Departamento
de Informática da UFPR) estão armazenados em um único arquivo, sendo que algumas linhas
possuem campos com ponto e vírgula entre as aspas. Dessa forma, foram propostos os seguintes
problemas:
Parte 2 : obter em um arquivo separado a lista de locais (coluna 5 do arquivo) de forma única e
ordenada;
Parte 3 : para cada código de local da lista de locais obtida na parte 2 (exemplo de local:
2100.13.01.02), criar um arquivo cujo nome seja o código com a extensão .csv
(exemplo de arquivo: 2100.13.01.02.csv) que contenha todas, e apenas, as linhas do
arquivo de entrada que contenham este padrão. (exemplo de conteúdo para o arquivo
2100.13.01.02.csv, ele contém todas as linhas que contém a string "2100.13.01.02").
1 # !/ bin / bash
2
8 egrep ' ^ ( \ " [ ^ \ ; ] ? \ " \ ; ) {5} $ ' patrimonio . csv > $ { tmp_file }
9
10 cut −d '; ' −f5 $ { tmp_file } | sort −u | sed 's =\"== g ' > $ { locals_file }
24
11
12
19 rm $ { tmp_file }
6.3 Problema 2
O número de matrículas em cada disciplina do DInf (Departamento de Informática da
UFPR) entre os anos de 1988 (primeiro semestre) até 2002 (segundo semestre) estão armazenados
em uma pasta "DadosMatricula", onde há um subdiretório para cada disciplina que o DInf
ministrava no período em análise. Dentro de cada um desses, existe um arquivo para cada
ano/semestre contendo dados de matrícula na respectiva disciplina.
Cada arquivo contém duas colunas: o código do curso cujo aluno se matriculou na
disciplina (exemplo: a engenharia civil é o código 02) e o GRR deste aluno. O cabeçalho dos
arquivos deve ser ignorado (pode ser apagado). O carcter separador de colunas é o ":"(dois
pontos). Sendo assim, foram propostos os seguintes problemas:
• Construir um script que dê como saída um arquivo que contém o total de matrículas
semestre a semestre considerando que os GRR’s não se repetem. O objetivo é ver
a evolução do número de matrículas semestre a semestre no período em análise. A
notação usa a concatenação do ano com o semestre, por exemplo, o primeiro semestre
de 1988 é denotado 19881.
1 # !/ bin / bash
2
9 mkdir −p anos
10
15 file = $ { file % % . }
16 name = $ { final_dir }/ $file " . txt "
17 sed '1 d ' $i >> $ { name }
18 done
19
29 declare −r courses = $ ( cat anos / . txt | cut −d ': ' −f1 | sort −u )
30 for s in $ { semester }
31 do
32 sem = $ { s # # / }
33 sem = $ { sem % % . }
34
37 cont =0
38 for c in $ { courses }
39 do
40 cont = $ (( $cont + 1 ) )
41
No código acima, as linhas que contém a palavra reservada declare do bash, são para
declarar variáveis. Elas são criadas somente para leitura com a opção -r, pois não são alteradas
ao longo do código. Vale ressaltar que a atribuição pode ser uma string dada diretamente, como
no caso das linhas de 3 a 6. ou pode ser resultado da execução de um comando, como no caso
das linhas de 11, 20 e 29. As quais, recebem a lista de todos os arquivos com extensão .dados, a
lista de todos os arquivos com extensão .txt, e a lista da primeira coluna de todos arquivos de
extensão .txt com uma ocorrência de cada valor, nos quais as colunas são separadas por dois
pontos (:), respectivamente.
O bloco for, que vai da linha 12 a 18, itera sobre todos os arquivos com a extensão
.dados que estão dentro das pastas das disciplinas, e joga seu conteúdo em um arquivo cujo nome
é o respectivo semestre. Sendo assim, todo conteúdo, excluindo a primeira linha (feito na linha
17 do script), dos arquivos cujo nome é 19881.dados será armazenado em um arquivo 19881.txt
dentro da pasta anos. Essa pasta é criada na linha 9 e seus arquivos são iterados no segundo
for nas linhas 21 a 27, de forma a pegar a segunda coluna dos mesmos, deixar apenas uma
27
ocorrência de cada valor e então contabilizar as entradas. Logo, ao final desse processo, obtem-se
um arquivo em que cada linha contém um semestre e seu respectivo número de matrículas.
No último for das linhas de 30 a 46, os arquivos da pasta anos também são utilizados.
Primeiramente é apenas utilizado o nome para pegar o semestre, e em um segundo momento feito
dentro do for das linhas 38 a 44, são percorridos para contabilizar quantas entradas correspondem
a cada um dos valores da variável da linha 29. Sendo assim, cria-se um arquivo onde cada linha
possui um semestre e o respectivo número de matrículas em cada curso encontrado na primeira
coluna (os valores da variável da linha 29), sendo formatado na linha 46. Nela, um aspecto
interessante de blocos for no bash pode ser observado: como são de certa forma comandos, sua
saída pode ser redirecionada a outro comando através do pipe (|)
Alguns pontos importantes dentro dos laços for devem ser notados e explicados. Nas
linhas 14 e 15, bem como as linhas 24 e 25, e 32 e 33, são utilizadas expansões de parâmetros
para guardar apenas a parte que interessa de uma string. Desse modo, a forma ##*/ remove
tudo que vem antes da última ocorrência da barra (/) no caminho do arquivo, incluindo a barra
e partindo do começo da string. E a forma %%*. remove tudo o que vem antes da primeira
ocorrência do ponto (.), incluindo o ponto, partindo do final da string.
6.5 Problema 3
Um firewall gera logs diários contendo informações dos pacotes que foram barrados por
casarem com alguma regra de filtragem. Um administrador de sistemas está interessado em saber
o total de bloqueios por tipo de regra de filtragem, por exemplo para enviar alertas de possíveis
comportamentos anormais que tipicamente podem ocorrer em casos de ataques.
O log é diário e pode ocorrer de alguma regra não ter sido filtrada em um determinado
dia, neste caso, queremos que seja impresso um zero, explicitando que não houve problema para
aquela regra naquele dia ao invés de simplesmente não imprimir a totalização para aquela regra.
Com isso se consegue observar um histórico periódico (semanal, mensal, anual) para que se
consiga observar um comportamento médio.
Dessa forma, o objetivo do trabalho é, a partir do log do firewall e das regras apresentadas
como exemplo, gerar um arquivo de saída similar ao exemplo dado acima. O total de ocorrências
não deve ultrapassar 20.000 (vinte mil), pois é o limite aceito pelo administrador como de
filtragens normais.
Portanto, além de gravar em disco a saída diária, você deve enviar email para caso
alguma filtragem ocorra além do limite. Finalmente, supondo que existe um log para cada dia,
você também deve se preocupar para que os arquivos de saída tenham nomes únicos, usando para
isso a data do sistema. Um cuidado com a eficiência deve ser tomado, o script não pode demorar
mais do que meio segundo para o caso do exemplo fornecido.
28
12 # main loop
13 # done for every line in the archive
14 # arr : identifier ; []: access operator ; $6 : sixth column ; ++: increment
15 # get an array and use the sixth column of each line to index it ,
16 # where the sixth column its the type of occurrence
17 # increment the indexed value
18 {
19 arr [ $6 ]++
20 }
21
No código em linguagem awk acima, as linhas que começam com o símbolo # e que estão
em verde são os chamados comentários da linguagem e não são interpretados como comandos a
29
serem executados, ou seja, são ignorados pelo compilador da linguagem. Já as demais linhas, são
comandos a serem executados ou indicadores de que comandos virão a seguir.
Nessa linguagem, um script é composto por três blocos delimitados por { e }. Onde o
primeiro serve para inicializações e comandos executados antes do processamento do texto de
entrada (geralmente um arquivo). O segundo contém comandos que serão executados para cada
linha do arquivo, e o terceiro são comandos executados após o processamento de arquivo, os
quais normalmente consistem de impressões.
Na linha 9 do script é visto o único comando do bloco BEGIN (primeiro bloco),
que limpa o arquivo temporário, fazendo o redirecionamento de nada para dentro do arquivo.
Seguindo para o loop principal, que pega um vetor, utiliza sua sexta coluna como índice, sendo
ela o tipo de ocorrência, e então incrementa o número de vezes em que aparece no vetor (arquivo
de entrada).
Por fim, o último bloco (END), percorre esse vetor e imprime qual o tipo de ocorrência
e o número de vezes em que aparece no arquivo de entrada. Como uma notificação deve ser
enviada por email para os tipos que aparecem mais de 20.000 vezes no log, eles são escritos no
arquivo temporário citado acima, juntamente com suas quantidades correspondentes na linha 33
do script.
Além disso, o comando da linha 38 faz uma chamada ao script em linguagem bash,
mostrado abaixo, que envia o email contendo os tipos acima do limite. Essa chamada, ocorre de
forma que o script bash executa em background. Nele, o comando mail presente na linha 7 do
mesmo envia o email, onde -s significa que segue o assunto do email e < redireciona o conteúdo
do arquivo como corpo da mensagem.
1 # !/ bin / bash
2
3 # send email
4 # −s : precedes the subject of the email
5 # <: redirects the file to the command ,
6 # so that its contents will be the message in the email
7 mail −s " Protocols over limit , please check . " jer14@inf . ufpr . br < " tmp_file . txt "
7 Conclusão
Referências
[11] C. Newham and B. Rosenblatt. Learning the bash shell: Unix shell programming. "O’Reilly
Media, Inc.", 2005.