bash/01/README.org

292 lines
10 KiB
Org Mode

#+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 /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.
** Expansão condicional
O Bash pode modificar os dados expandidos de muitas formas. Entre elas, nós temos
a possibilidade de expandir strings condicionalmente com:
#+begin_example
${NOME:-STRING}
#+end_example
Caso ~NOME~ não tenha sido definida ou não tenha um valor associado, o shell
expandirá ~STRING~.
Exemplo:
#+begin_example
:~$ var=
:~$ echo ${var:-um valor padrão}
um valor padrão
:~$ var=banana
:~$ echo ${var:-um valor padrão}
banana
#+end_example
Sem o ~:~, STRING só é expandida se a variável ~NOME~ não estiver definida:
#+begin_example
:~$ echo ${xxx:-valor padrão} # A variável 'xxx' não está definida
valor padrão
:~$ echo ${xxx-valor padrão} # Sem ':', ainda temos a expansão
valor padrão
:~$ xxx= # Definindo 'xxx' com valor vazio
:~$ echo ${xxx-valor padrão} # Sem ':', nada é expandido
:~$
#+end_example