#+title: Shell Script na Prática #+author: Blau Araujo #+email: blau@debxp.org * Desafio 1: Salve, simpatia ** Objetivos - O que é um shell - O que são scripts - Como criá-los - Como executá-los - Como imprimir mensagens no terminal - O que são variáveis - O que são argumentos - O que são parâmetros - O que são expansões de parâmetros ** Enunciado Imprimir a mensagem ~Salve, simpatia!~ no terminal. ** Evolução 1 Tornar o conteúdo da mensagem dependente do valor associado à variável ~nome~, que substituirá a palavra ~simpatia~. ** Evolução 2 Tornar o conteúdo da mensagem dependente do primeiro argumento passado na invocação do script, que substituirá a palavra ~simpatia~. ** Evolução 3 Tornar a impressão da palavra ~simpatia~ condicionada à ausência do primeiro argumento na invocação do script. ----- * Anotações da aula 1 ** O que é um shell Em sistemas parecidos com o Unix (/unix-like/), como o GNU/Linux, o shell é um programa que exerce três funções básicas: *Interface padrão entre o usuário e o sistema:* - Quando um terminal é disponibilizado para o usuário, um shell é iniciado para que o usuário digite seus comandos; - Quando o usuário tecla =ENTER=, a linha com o seu comando é enviado para o shell; - O shell, então, inicia o processamento da linha do comando para determinar o que deve ser executado; - Ao fim do processamento, o shell providencia a execução do que foi solicitado pelo usuário. *Interpretador de comandos:* No papel de interpretador, o shell deve processar a linha do comando digitado pelo usuário a fim de determinar o que deve ser executado. O shell pode interpretar comandos de dois modos: - *Modo interativo:* os comandos são digitados diretamente no terminal e executados um a um. - *Modo não interativo:* os comandos são escritos antes do shell ser executado para interpretá-los, como em scripts ou como argumentos da opção =-c= do shell. *Plataforma de operação do sistema:* Como o shell é a interface padrão do sistema, além de seus comandos e mecanismos internos, inúmeros programas, para as mais diversas finalidades, são criados para serem utilizados no terminal através do shell, o que termina por constituir um ambiente de operação completo e coerente (uma /plataforma/) para a execução de tarefas e operação do sistema. ** O que é um comando Um /comando/ é a expressão da vontade do usuário na forma de uma linha de texto escrita segundo uma sintaxe bem definida. Na sua forma mais simples, um comando é composto por: #+begin_example [EXPORTAÇÕES] [[INVOCAÇÃO] [ARGUMENTOS]] [REDIRECIONAMENTOS] #+end_example Onde: - *Exportações:* Atribuições de /nomes/ a variáveis, no formato ~NOME=VALOR~, que serão exportadas para o programa ou comando que for /invocado/; caso a linha não tenha uma ~INVOCAÇÃO~, as variáveis serão definidas para uso no próprio shell. - *Invocação:* Palavra que corresponde ao que deve ser executado, podendo ser o nome do arquivo executável ou um comando interno do shell (/builtin/). - *Argumentos:* Todas as palavras escritas depois do nome do que estiver sendo invocado é interpretada como /argumento/ da invocação e serão passadas para o que vier a ser executado. - *Redirecionamentos:* O que define o fim da lista de palavras que compõem a ~INVOCAÇÃO~ e seus eventuais ~ARGUMENTOS~ é o fim da linha ou a presença de um /operador/; se o operador for composto pelos caracteres ~<~ ou ~>~, eles indicarão que os dados produzidos pelo comando (a sua /saída/), em vez de serem exibidos no terminal, serão escritos em um arquivo ou, na direção contrária, que o comando receberá dados através da leitura de um arquivo. ** O que são scripts Scripts são arquivos-texto contendo os comandos que o shell deve executar de modo /não interativo/. Como parte de seus mecanismos internos, o shell oferece diversos recursos para controlar como, quando e com que dados os comandos devem ser executados -- em outras palavras, esses mecanismos tornam possível a criação de /programas/. ** Como criá-los Para criar um script, basta criar um arquivo-texto com os comandos. Para isso, nós precisamos de um editor (como: Vim, Nano, Micro, Emacs, etc) ou podemos utilizar os próprios recursos do shell. ** Como executá-los O conteúdo do script terá que ser interpretado e executado pelo shell, o que pode ser feito de duas formas básicas: *Arquivos sem permissão de execução* Apenas arquivos com o atributo de execução ativados podem ser executados a partir da invocação de seus nomes. Sem essa permissão, o nome do arquivo do script pode ser passado como argumento da invocação do shell: #+begin_example :~$ bash meu-script.sh #+end_example *Arquivos com permissão de execução* Se o atributo de execução estiver ativo, e o usuário tiver permissão para executá-lo, basta invocar o caminho e o nome do arquivo do script: #+begin_example :~$ ./script1.sh # O script está no diretório onde é invocado. :~$ ~/bin/script2.sh # O script está em /home/usuário/bin. #+end_example Contudo, quando iniciado no modo /interativo/, o shell recebe uma variável, de nome ~PATH~, cujo valor associado é uma lista de diretórios em que arquivos executáveis devem ser procurados. Se o script estiver em algum desses diretórios, basta invocar seu nome: #+begin_example :~$ meu-script.sh #+end_example ** Como o script é executado A não ser que um interpretador seja especificado (ou invocado), todo arquivo-texto será lido e executado como se contivesse apenas comandos do shell em execução no terminal. Para especificar um interpretador no próprio script, ele deve iniciar com uma /hashbang/ (~#!~), ou /linha do interpretador de comandos/. No caso do Bash, a /hashbang/ pode ser escrita de várias formas: - ~#!/bin/bash~ - ~#!/usr/bin/bash~ - ~#!/usr/bin/env bash~ A presença da /hashbang/ na primeira linha do script diz ao shell quem deverá ser utilizado para executar o conteúdo do arquivo. Internamente, isso tem o mesmo efeito de: #+begin_example :~$ /bin/bash SCRIPT #+end_example ** Como imprimir mensagens no terminal Existem várias formas, mas o shell tem dois comandos internos dedicados a essa finalidade: - ~echo~: imprime seus argumentos separados por um espaço e com uma quebra de linha do final. - ~printf~: imprime seus argumentos conforme uma formatação especificada como primeiro argumento. ** O que são variáveis No shell, variáveis são /nomes/ que identificam valores que podem ser criados e alterados. Para ser válido como identificador de uma valor, o nome deve conter apenas caracteres alfabéticos maiúsculos e minúsculos, o caractere sublinhado (~_~) e números, mas não pode começar com números. ** O que são parâmetros O shell também faz associações entre identificadores e valores com variáveis. Mas, os valores que não podem ser criados ou alterados diretamente por nós são identificados por caracteres inválidos para /nomes/ (como números e outros símbolos gráficos). Esses identificadores são chamados de /parâmetros/ e podem ser classificados como /parâmetros posicionais/ e /parâmetros especiais/. *Parâmetros posicionais:* | Identificador | Valor associado | |---------------+--------------------------------------------------------------| | ~0~ | A palavra utilizada como ~INVOCAÇÃO~ na linha do comando | | ~1..N~ | Cada palavra utilizada como ~ARGUMENTO~ conforme sua posição. | | ~#~ | A quantidade de argumentos (exclui a invocação da contagem). | | ~@~ | A lista de todas as palavras utilizadas como argumentos. | | ~*~ | A lista de todas as palavras utilizadas como argumentos. | *Parâmetros especiais:* | Identificador | Valor associado | |---------------+----------------------------------------------------------| | ~-~ | As opções de início do shell (na forma de caracteres) | | ~$~ | O número do /processo/ do shell em execução. | | ~?~ | O estado de término do último comando (sucesso ou erro). | | ~!~ | O número do último processo executado em segundo plano. | ** O que são expansões de parâmetros No shell, tanto variáveis quanto parâmetros são chamados de /parâmetros/ e seus valores são acessados através do mecanismo da /expansão/, que é o nome dado a qualquer troca de símbolos ou identificadores na linha do comando pelos seus respectivos valores. No caso de variáveis e parâmetros, a expansão é indicada para o shell com o caractere ~$~ escrito no início do identificador: #+begin_example $IDENTIFICADOR # Expande o valor associado a IDENTIFICADOR. ${IDENTIFICADOR} # Forma utilizada quando a expansão é modificada # ou quando IDENTIFICADOR pode ser confundido com # os caracteres seguintes na linha. #+end_example A coisa mais importante a saber sobre as expansões, é que elas são processadas *antes* da linha do comando ser efetivamente executada. Portanto, no exemplo abaixo... #+begin_example :~$ fruta=bananas :~$ echo Vou comprar $fruta. Vou comprar bananas. #+end_example A variável ~fruta~ teve seu valor expandido antes do comando ~echo~ ser executado.