Programação Shell LinuxAqui temos um livro livre e completo sobre ShellOs sedentos do "saber livre" são muito benvindos. |
Comandos Shell Script |
||
Home | Artigos | Agradecimentos | Links Amigos | Comprar o livroChangelogs |
Papo de Botequim - Parte 1Papo de Botequim - Parte 2Papo de Botequim - Parte 3Papo de Botequim - Parte 4Papo de Botequim - Parte 5Papo de Botequim - Parte 6Papo de Botequim - Parte 7Papo de Botequim - Parte 8Papo de Botequim - Parte 9Papo de Botequim - Parte 10Papo de Botequim - Parte 11Tira Gosto |
Papo de Botequim - Parte II- Garçom! Traz um "chops" e dois "pastel". O meu amigo hoje não vai beber por que ele finalmente está sendo apresentado a um verdadeiro sistema operacional e ainda tem muita coisa a aprender! - E então, amigo, tá entendendo tudo que te expliquei até agora? - Entendendo eu tô, mas não vi nada prático nisso... - Calma rapaz, o que te falei até agora, serve como base ao que há de vir daqui pra frente. Vamos usar estas ferramentas que vimos para montar programas estruturados, que o Shell permite. Você verá porque até na TV já teve programa chamado "O Shell é o Limite". - Para começar vamos falar dos comandos da família - - É claro, Eu fico com o
|
Posição | 1ª | 2ª | 3ª | 4ª |
---|---|---|---|---|
- |
||||
Valores Possíveis | - |
r |
w |
x |
- |
- |
s (suid) |
Assim sendo, para descobrir todos os arquivos executáveis em um determinado diretório eu deveria fazer:
Onde novamente usamos o circunflexo (^
) para limitar a pesquisa ao início de cada linha, então as linhas listadas serão as que começam por um traço (-
), seguido de qualquer coisa (o ponto quando usado como uma expressão regular significa qualquer coisa), novamente seguido de qualquer coisa, vindo a seguir um x
ou um s
.
Obteríamos o mesmo resultado se fizéssemos:
e agilizaríamos a pesquisa.
Vamos começar a desenvolver programas, acho que a montagem de um banco de dados de músicas é bacana para efeito didático (e útil nesses tempos de downloads de mp3 e "queimadores" de CDs). Não se esqueça que, da mesma forma que vamos desenvolver um monte de programas para organizar os seus CDs de música, com pequenas adaptações, você pode fazer o mesmo com os CDs de software que vêm com a Linux Magazine e outros que você compra ou queima, disponibilizando este banco de software para todos que trabalham com você (o Linux é multiusuário, e como tal deve ser explorado), desta forma ganhando muitos pontos com seu adorado chefe.
- Péra ai! De onde eu vou receber os dados dos CDs?
- Inicialmente, vou lhe mostrar como o seu programa pode receber parâmetros de quem o estiver executando e em breve, ensinarei a ler os dados pela tela ou de um arquivo.
O layout do arquivo musicas será o seguinte:
nome do álbum^intérprete1~nome da música1:..:intérprete~nome da música
isto é, o nome do álbum será separado por um circunflexo (^
) do resto do registro, que é formado por diversos grupos compostos pelo intérprete de cada música do CD e a respectiva música interpretada. Estes grupos são separados entre si por dois-pontos (:
) e internamente, o intérprete será separado por um til (~
) do nome da música.
Eu quero escrever um programa que chamado musinc
, que incluirá registros no meu arquivo musicas. Eu passarei o conteúdo de cada álbum como parâmetro na chamada do programa fazendo assim:
Desta forma o programa musinc
estará recebendo os dados de cada álbum como se fosse uma variável. A única diferença entre um parâmetro recebido e uma variável é que os primeiros recebem nomes numéricos (nome numérico fica muito esquisito, né? O que quis dizer é que seus nomes são formados por um e somente um algarismo), isto é $1, $2, $3, ..., $9
. Vamos, antes de tudo, fazer um teste:
Exemplos
Vamos executá-lo:
Ops! Esqueci-me de torná-lo executável. Vou fazê-lo de forma a permitir que todos possam executá-lo e em seguida vou testá-lo:
Repare que a palavra testar
, que seria o quarto parâmetro, não foi listada. Isto deu-se justamente porque o programa teste só listava os três primeiros parâmetros. Vamos executá-lo de outra forma:
As aspas não deixaram o Shell
ver o espaço em branco entre as palavras e considerou-as um único parâmetro.
Já que estamos falando em passagem de parâmetros deixa eu te dar mais umas dicas:
Significado das Principais Variáveis Referentes aos Parâmetros | |
---|---|
$* |
Contém o conjunto de todos os parâmetros (muito parecido com $@ ) |
Variável | Significado |
$0 |
Contém o nome do programa |
$# |
Contém a quantidade de parâmetros passados |
Exemplos
Vamos alterar o programa teste
para usar as variáveis que acabamos de ver. Vamos fazê-lo assim:
Repare que antes das aspas eu usei uma barra invertida para o escondê-las da interpretação do Shell (se não usasse as contrabarras as aspas não apareceriam). Vamos executá-lo:
Conforme eu disse, os parâmetros recebem números de 1
a 9
, mas isso não significa que não posso usar mais de 9 parâmetros significa somente que só posso endereçar 9. Vamos testar isso:
Exemplo:
Vamos executá-lo:
Duas coisas muito interessantes neste script:
$1
a $9
eu fiz um echo $11
e o que aconteceu? O Shell interpretou como sendo $1
seguido do algarismo 1
e listou passando1
;
shift
cuja sintaxe é shift n
, podendo o n
assumir qualquer valor numérico (porém seu default é 1
como no exemplo dado), despreza os n
primeiros parâmetros, tornando o parâmetro de ordem n+1
, o primeiro ou seja, o $1
.
Bem, agora que você já sabe mais sobre passagem de parâmetros do que eu, vamos voltar à nossa "cdteca" para fazer o script de inclusão de CDs no meu banco chamado musicas
. O programa é muito simples (como tudo em Shell) e vou listá-lo para você ver:
Exemplos
O script é fácil e funcional, limito-me a anexar ao fim do arquivo musicas
o parâmetro recebido. Vamos cadastrar 3 álbuns para ver se funciona (para não ficar "enchendo lingüiça", vou supor que em cada CD só existem 2 músicas):
Listando o conteúdo de musicas.
Não está funcional como achava que deveria ficar... podia ter ficado melhor. Os álbuns estão fora de ordem, dificultando a pesquisa. Vamos alterar nosso script e depois testá-lo novamente:
Vamos cadastrar mais um:
Agora vamos ver o que aconteceu com o arquivo musicas
:
Simplesmente inseri uma linha que classifica o arquivo musicas
dando a saída nele mesmo (para isso serve a opção -o
), após cada álbum ser anexado.
Oba! Agora está legal e quase funcional. Mas atenção, não se desespere! Esta não é a versão final. O programa ficará muito melhor e mais amigável, em uma nova versão que desenvolveremos após aprendermos a adquirir os dados da tela e formatar a entrada.
Exemplos
Ficar listando com o comando cat
não está com nada, vamos então fazer um programa chamado muslist
para listar um álbum cujo nome será passado como parâmetro:
Vamos executá-lo, procurando pelo album 2
. Como já vimos antes, para passar a cadeia album 2
é necessário protegê-la da interpretação do Shell, para que ele não a interprete como dois parâmetros. Vamos fazer assim:
Que lambança! Onde está o erro? Eu tive o cuidado de colocar o parâmetro passado entre aspas, para o Shell não dividi-lo em dois!
É, mas repare como está o grep
executado:
grep $1 musicas
Mesmo colocando álbum 2
entre aspas, para que fosse encarado como um único parâmetro, quando o $1
foi passado pelo Shell para o comando grep
, transformou-se em dois argumentos. Desta forma o conteúdo final da linha, que o comando grep
executou foi o seguinte:
grep album 2 musicas
Como a sintaxe do grep
é:
=grep
o grep
entendeu que deveria procurar a cadeia de caracteres album
nos arquivos 2
e musicas
, Por não existir o arquivo 2
gerou o erro, e por encontrar a palavra album
em todos os registros de musicas
, listou a todos.
cadeia de caracteres
a ser passada para o comando grep
possuir brancos ou TAB
, mesmo que dentro de variáveis, coloque-a sempre entre aspas para evitar que as palavras após o primeiro espaço em branco ou TAB
sejam interpretadas como nomes de arquivos.
Por outro lado, é melhor ignorarmos maiúsculas e minúsculas na pesquisa. Resolveríamos os dois problemas se o programa tivesse a seguinte forma:
Neste caso, usamos a opção -i
do grep
, que como já vimos, serve para ignorar maiúsculas e minúsculas, e colocamos o $1
entre aspas, para que o grep
continuasse a ver a cadeia de caracteres resultante da expansão da linha pelo Shell
como um único argumento de pesquisa.
Agora repare que o grep
localiza a cadeia pesquisada em qualquer lugar do registro, então da forma que estamos fazendo, podemos pesquisar por álbum, por música, por intérprete ou até por um pedaço de qualquer um destes. Quando conhecermos os comandos condicionais, montaremos uma nova versão de muslist
que permitirá especificar por qual campo pesquisar.
Aí você vai me dizer:
- Poxa, mas é um saco ter que colocar o argumento de pesquisa entre aspas na hora de passar o nome do álbum. Esta forma não é nem um pouco amigável!
- Tem razão, e por isso vou te mostrar uma outra forma de fazer o que você pediu:
Desta forma, o $*
, que significa todos os parâmetros, será substituído pela cadeia album 2
(de acordo com o exemplo anterior, fazendo o que você queria.
Não se esqueça o problema do Shell não é se você pode ou não fazer uma determinada coisa. O problema é decidir qual é a melhor forma de fazê-la, já que para desempenhar qualquer tarefa, a quantidade de opções é enorme.
Ah! Em um dia de verão você foi à praia, esqueceu o CD no carro, aquele "solzinho" de 40 graus empenou o seu CD e agora você precisa de uma ferramenta para removê-lo do banco de dados? Não tem problema, vamos desenvolver um script chamado musexc
, para excluir estes CDs.
Antes de desenvolver o "bacalho", quero te apresentar a uma opção bastante útil da família de comandos grep
. É a opção -v
, que quando usada lista todos os registros da entrada, exceto o(s) localizado(s) pelo comando. Vejamos:
Exemplos
Conforme eu expliquei antes, o grep
do exemplo listou todos os registros de musicas exceto o referente a album 2
, porque atendia ao argumento do comando. Estamos então prontos para desenvolver o script para remover aquele CD empenado da sua "CDteca". Ele tem a seguinte cara:
Na primeira linha mandei para /tmp/mus$$
o arquivo musicas, sem os registros que atendessem a consulta feita pelo comando grep
. Em seguida, movi (que, no duro, equivale a renomear) /tmp/mus$$
por cima do antigo musicas
.
Usei o arquivo /tmp/mus$$
como arquivo de trabalho, porque como já havia citado no artigo anterior, o $$
contém o PID
(Process Identification ou identificação do processo) e desta forma cada um que editar o arquivo musicas
o fará em um arquivo de trabalho diferente, desta forma evitando colisões no uso.
- Aê cara, estes programas que fizemos até aqui estão muito primários em virtude da falta de ferramentas que ainda temos. Mas é bom, enquanto eu tomo mais um chope, você ir para casa praticar em cima dos exemplos dados porque, eu prometo, chegaremos a desenvolver um sistema bacana para controle dos seus CDs.
- Quando nos encontrarmos da próxima vez, vou te ensinar como funcionam os comandos condicionais e aprimoraremos mais um pouco estes scripts.
- Por hoje chega! Já falei demais e preciso molhar a palavra porque estou de goela seca!
- Garçom! Mais um sem colarinho!
Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em Shell que mande um e-mail para a nossa gerencia de treinamento para informar-se.
Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para mim.
Valeu!