Shell script
# Shell script

Shell script é o nome dado a um arquivo que será interpretado por algum programa tipo Shell. Atualmente existem vários programas tipo Shell. Além dos principais - sh e bash -, existem também, ksh, zsh, csh e tcsh. Um Shell script (ou script em Shell) necessita basicamente do interpretador Shell.
Algumas operações típicas executadas por linguagens de script em Shell incluem; manipulação de arquivos, execução de programas e impressão de texto. Sendo assim é muito comum que scripts sejam utilizados para automatização de tarefas - como configurar o ambiente, executar um programa e fazer qualquer limpeza, registro, etc. Essas tarefas executadas por scripts em Shell são conhecidas mais popularmente como Shell Wrappers.

## História

A primeira linguagem de script em Shell, criada por Stephen R. Bourne, veio a ser implementada na versão 7 do Unix Shell e ficou conhecida como Bourne Shell (sh). Após a sua implementação, diversas outras linguagens de scripts baseadas no sh vieram, tais como Korn Shell, e DMERT Shell, sendo que, em 1989, foi lançada a linguagem que se tornou Shell de login padrão em diversas distribuições Linux, a GNU Bash ou simplesmente Bash.

## Funcionalidades e Capacidades
### Selecionar Shell

Para selecionar qual Shell será utilizado, use a combinação de hashtag (#) mais exclamação (!) e caminho do executável na primeira linha do arquivo script, isso vem a ser conhecido como Shebang.
- Para declarar que o script deve ser interpretado por Bourne Shell (sh) a primeira linha será escrita da seguinte forma:
- Para declarar que o script deve ser interpretado por Bourne-Again shell (Bash) é recomendável a utilização do comando env, pelo fato que apesar de o Bash já vir instalado em muitas distribuições Linux, não sabemos se estará em todas elas no mesmo diretório /bin/, então use a seguinte forma:

### Comentários

Os comentários nas linguagens Bourne Shell (sh) e Bourne-Again Shell (bash) serão utilizados hashtag (#), Exemplo de comentários:

### Variáveis

Como qualquer outra linguagem de programação conhecida, um script em Shell também possui suporte a variáveis. Em uma breve explicação uma variável é um nome/objeto simbólico ao qual podemos atribuir valores, ler ou manipular o conteúdo. Para mais informações, leia-me. Os scripts em Shell podem lidar com diferentes tipos de variáveis sem precisar definir o tipo:

#### Variáveis Pré-definidas

Os scripts em Shell possuem as seguintes variáveis pré-definidas:
* $? - Armazena o status de saída do último programa executado;
* $# - Armazena a quantidade de parâmetros de linha de comandos;
* $$ - Armazena o valor PID (Process Identifier) do script em shell que estiver em execução;
* $@ - Armazena o valor de todos os parâmetros passados, similar a variável argv presente nas linguagens de programação C e C++;
* $! - Armazena o PID do último processo em segundo plano. Isso é útil para acompanhar o processo à medida que o trabalho é realizado;
* $0, ..., $9 - Armazena os valores de todos os parâmetros de linha de comando separadamente;

#### Variáveis Globais

Variáveis globais ou variáveis de ambiente globais, são variáveis criadas/definidas com o comando export e podem ser utilizadas por múltiplos scripts em Shell. Um exemplo é a variável de ambiente LANG (Pré-definida em diversas distribuições Linux), Podendo ser acessada por diversos arquivos de script em Shell.
Outras variáveis pré definidas são:
* PATH: define diretórios de procura por programas executados no shell;
* USER: informa o nome do usuário do shell;
* HOME: informa o caminho do diretório home do usuário;
* LANG: Idioma/Linguagem, especificada como locale;
* PWD: diretório atual;
* TERM: Tipo de terminal atual em uso.
* UID: UID do usuário atual.
* RANDOM: Gera um número aleatório
A duas formas de criar uma variável global, exportar uma variável pré definida ou definir quando for exportar:

#### Array

Bourne Shell (sh) não é compatível com variáveis tipo array, mas Bourne-Again Shell (Bash) sim, exemplo simples de implementação:

#### Array Associativo

Podemos construir em Bash arrays associativos, também chamados de dicionários

#### Chamar variáveis

Para chamar variáveis utiliza-se o sinal de cifrão $var. O cifrão ($) também é bastante utilizado em script sh, para executar programas externos exemplo: var=$(expr 2 + 2) irá armazenar a saída do programa expr. E o cifrão mais chave ${var} é comum ser utilizado das seguintes maneiras:
Para acessar posições em um array ${var[1]}. (obs.: não funciona para sh, apenas para Bash)
E também para substituir o valor de uma variável se a mesma não possuir um valor: ${var:-nome} - ${var:=nome} - ${var:-$(programa)} dessas maneiras irão substituir pelo que for passado depois de :- ou :=, exemplo em código:
O código acima irá pedir para o usuário digitar um nome, caso digite irá utilizar echo para imprimir o nome digitado na saída padrão, caso contrário irá substituir pela saída do comando whoami, ao invés de substituir pela saída de um comando, você pode substituir por outro valor exemplo: ${myname:=Bourne Shell}.

##### Remover Variáveis

Para remover uma variável, utiliza-se o comando unset + nome da variável, você pode também remover múltiplas variáveis basta separá-las por espaços.

### If

Declaração if para scripts em bash ou sh:
Existe também outra forma:

### If-else

Declaração if else para scripts em bash ou sh, há diversas formas diferentes, tenha cuidado para não esquecer os espaços entre os colchetes eles são muito importantes:
A declaração if else mais comum e mais utilizada é a seguinte:
Mas, existe uma abreviação que também é muito utilizada que é menor e muito boa para teste de linha única:

### Else-if

Declaração else if para scripts em bash ou sh são diferentes de algumas linguagens de programação, exemplo:

### Case

Scripts em Bash ou sh, permitem case, a sintaxe é a seguinte:

### Expressões Regulares

Scripts em Bash possui compatibilidade com Expressões Regulares, algo que scripts em Bourne Shell (sh) não reconhecem:

### Operadores

Existem diversos operadores para cada Shell script, mas aqui serão passadas informações especificamente sobre Bourne shell por ser mais comum e muitos outros shell são similares. Os seguintes operadores serão explicados aqui:

#### - Operadores Aritméticos

| Operadores | Descrição | Exemplos |
| + (Adição) | Utilizado para somar valores em ambos lados do operador | $(expr 10 + 20) será igual 30 |
| - (Subtração) | Utilizado para subtrair valores do lado direito para o esquerdo | $(expr 20 - 30) será igual -10 |
| *(Multiplicação) | Utilizado para multiplicar valores em ambos lados do operador | $(expr 2 \* 6) será igual a 12 |
| / (Divisão) | Utilizado para dividir o valor esquero pelo direito do operador | $(expr 12 / 6) será igual a 2 |
| % (Módulo) | Utilizado para dividir o valor da esquerda pelo da direita e retornar o restante | $(expr 12 % 6) será igual a 0 |
| = (Igual) | Utilizado para atribuir valores e para testar valores. | x=2 Atribui o valor 2 para variável x. [ $x = 2 ] Se $x é igual a 2 |
| != (Não igual) | Utilizado para testas se um valor é diferente de outro. | [ $x != 3 ] Se $x é diferente de 3 |

#### - Operadores Booleanos

| Operadores | Descrição | Exemplos |
| ! (Diferente) | Conhecido como Operador Lógico de negação. Utilizado para inverter uma condição de verdadeira para falsa e vice versa. | [ ! $x = 22 ] Se o valor de x é diferente de 22. |
| -o (ou) | Conhecido como Operador Lógico OR. Utilizado para testar duas ou mais possibilidades. | [ $x = 22 -o $x = 23 ] Se o valor de x é igual a 22 ou 23 |
| -a (e) | Conhecido como Operador Lógico AND. Utilizado para testar duas ou mais possibilidades. | [ $y = 22 -a $x = 22 ] Se o valor de x e y são iguais a 22 |

#### - Operadores para Teste de Arquivos

| Operadores | Descrição | Exemplos |
| -b arquivo | Verifica se o arquivo é um arquivo especial de bloco; se sim, então a condição se torna verdadeira. | [ -b /etc/resolv.conf ] |
| -c arquivo | Verifica se o arquivo é um arquivo especial de caracteres; se sim, então a condição se torna verdadeira. | [ -c /etc/resolv.conf ] |
| -d arquivo | Verifica se o arquivo é um diretório; se sim, então a condição se torna verdadeira | [ -d /etc/resolv.conf ] |
| -f arquivo | Verifica se arquivo é um arquivo comum em oposição a um diretório ou arquivo especial; se sim, então a condição se torna verdadeira. | [ -f /etc/resolv.conf ] |
| -g arquivo | Verifica se o arquivo possui o seu conjunto de bits de identificação de grupo (SGID); se sim, então a condição se torna verdadeira. | [ -g /etc/resolv.conf ] |
| -k arquivo | Verifica se o arquivo tem seu bit fixo definido; se sim, então a condição se torna verdadeira. | [ -k /etc/resolv.conf ] |
| -p arquivo | Verifica se o arquivo é um pipe nomeado; se sim, então a condição se torna verdadeira. | [ -p /etc/resolv.conf ] |
| -t arquivo | Verifica se o descritor de arquivo está aberto e associado a um terminal; se sim, então a condição se torna verdadeira. | [ -t /etc/resolv.conf ] |
| -u arquivo | Verifica se o arquivo tem seu bit Set ID do usuário (SUID) definido; se sim, então a condição se torna verdadeira. | [ -u /etc/resolv.conf ] |
| -r arquivo | Verifica se o arquivo está legível; se sim, então a condição se torna verdadeira. | [ -r /etc/resolv.conf ] |
| -w arquivo | Verifica se o arquivo é gravável; se sim, então a condição se torna verdadeira. | [ -w /etc/resolv.conf ] |
| -x arquivo | Verifica se o arquivo é executável; se sim, então a condição se torna verdadeira. | [ -x /etc/resolv.conf ] |
| -s arquivo | Verifica se o arquivo tem tamanho maior que 0; se sim, então a condição se torna verdadeira. | [ -s /etc/resolv.conf ] |
| -e arquivo | Verifica se o arquivo existe; é verdadeiro mesmo se o arquivo for um diretório, mas existe. | [ -e /etc/resolv.conf ] |

#### - Operadores Relacionais

| Operadores | Descrição | Exemplos |
| -eq | Verifica se o valor de dois operandos é igual ou não; se sim, então a condição se torna verdadeira. | [ $x -eq 2 ] |
| -ne | Verifica se o valor de dois operandos é igual ou não; se os valores não forem iguais, a condição se tornará verdadeira. | [ $x -ne 2 ] |
| -gt | Verifica se o valor do operando esquerdo é maior que o valor do operando direito; se sim, então a condição se torna verdadeira. | [ $x -gt 2 ] |
| -lt | Verifica se o valor do operando esquerdo é menor que o valor do operando direito; se sim, então a condição se torna verdadeira. | [ $x -lt 2 ] |
| -ge | Verifica se o valor do operando esquerdo é maior ou igual ao valor do operando direito; se sim, então a condição se torna verdadeira. | [ $x -ge 2 ] |
| -le | Verifica se o valor do operando esquerdo é menor ou igual ao valor do operando direito; se sim, então a condição se torna verdadeira. | [ $x -le 2 ] |

#### - Operadores de String

| Operadores | Descrição | Exemplos |
| -z | Verifica se o tamanho do operando da string fornecido é zero; se tiver comprimento zero, retornará verdadeiro. | [ -z $str ] |
| -n | Verifica se o tamanho do operando da string especificado é diferente de zero; se tiver um comprimento diferente de zero, retornará true. | [ -n $str ] |
| [ $uma_var ] | Verifica se Uma_var não é a string vazia; se estiver vazio, ele retornará false. | [ $str ] |

### Loop
#### For

Esse tipo de loop funciona da mesma forma para ambos Bash e sh.

#### While

Existem diversas formas de utilizar o loop while para scripts em Bash ou sh:

### Funções

O scripts em Shell também aceitam funções. Bash e sh aceitam um mesmo padrão de funções, mas o Bash também aceita um outro formato que o sh não reconhece. Ambos formatos são mostrados abaixo:
Para chamar uma função basta digitar o nome da função em uma linha após a declaração da função como se fosse um comando. Exemplo:

#### Status de saída

O status de saída de um comando executado são valores, retornados pela chamada do sistema waitpid ou função equivalente. Os valores para o status de saída ficam entre 0 e 255; Os status de saída dos Shell builtins e comandos compostos também são limitados a esse intervalo. Sob certas circunstâncias, o shell usará valores especiais para indicar modos de falha específicos.
Para os propósitos do Shell, um comando que sai com um status de saída igual a 0 (zero) significa que a execução do script foi bem-sucedida. Você pode ver os exemplos passados anteriormente onde a última linha do script o status de saída é 0 (zero). Já um status de saída diferente de zero indica falha. Esse esquema aparentemente contra-intuitivo é usado para que haja uma maneira bem definida de indicar sucesso e uma variedade de maneiras para indicar vários modos de falha.
Quando um comando termina em um sinal fatal cujo número é N, o Bash por exemplo usa o valor 128+N como status de saída. Se um comando não for encontrado, o processo filho criado para executá-lo retornará um status 127. Se um comando for encontrado, mas não for executável, o status de retorno será 126. Um exemplo de uma implementação simples de status de saída:
O próximo exemplo irá checar se um comando não foi executado com sucesso:
$^{Osscriptpassadosacimasãoparaexemplosdeimplementação..}$

## Exemplos de uso
### Criar Shell script

Para criar um Shell script você precisa saber, antes, qual linguagem de script irá utilizar . Se for utilizar Bash, por exemplo, basta criar um arquivo com a extensão .sh e colocar na primeira linha desse arquivo o shebang para bash.
Para distribuições com base Linux, abra o terminal e digite os seguintes comandos:
E depois de criado você deve tornar o arquivo executável, utilizando o seguinte comando: chmod u+x novo_script

### Verificar parâmetros de linha de comando

Para verificar parâmetros de linha de comando com Bourne shell, há apenas uma maneira recomendável: utilizar loop + case + shift. Já com Bash há mais de uma, pelo fato de o Bash suportar expressões regulares.
Testar parâmetros utilizando loop + case + shift:
O loop while acima irá iniciar se e somente se houver um parâmetro. O case irá analisar os parâmetros e o shift irá mudar de parâmetros se houver mais de um e terminar o loop caso não haja mais nenhum. Caso você tenha muitas opções para o seu script deixe help e version sempre como as primeiras e utilize break para terminar o loop.

### Apagar arquivos antigos

Apagar periodicamente arquivos mais velhos que 30 dias do diretório /tmp: