29 de mai de 2020 - 11 min de leitura
Shell Script
O que você precisa saber sobre shell script
Introdução - O que são Shell Scripts?
São scripts interpretados por algum programa Shell, sendo Shell uma interface de linha de comando (CLI) que permite o usuário acessar serviços do sistema operacional.
Nos exemplos desse artigo vamos utilizar o bash como interpretador.
O Bash está disponível por padrão nos sistemas operacionais Unix-like como Linux e macOS.
É recomendável que você tenha algum conhecimento básico do uso da CLI antes de começar a escrever shell scripts.
Índice
- Criando o primeiro script
- Strings
- Variáveis
- Matrizes
- Execução shell
- Entradas do usuário
- Operadores de comparação
- Condições
- Loops
- Funções
- Conclusão
- Agradecimentos
Criando o primeiro script
Crie o arquivo hello-world
:
# touch é o comando usado para criar um arquivo
touch hello-world
Dentro do arquivo vamos imprimir um texto usando o comando echo
:
echo "Hello, world!"
Agora, usando a linha de comando, podemos executar nosso script com o interpretador bash
:
bash hello-world
# Output: Hello, world!
Pronto, temos nosso primeiro shell script.
Scripts executáveis
Aprendemos a executar um script prefixado de bash, que é o responsável por interpretar os comandos dentro do nosso arquivo, mas se tentarmos simplesmente executar o arquivo pelo nome, ele não será executado.
./hello-world
# Output: bash: ./hello-world: Permissão negada
./
é usado para indicar que arquivo está no diretório atual
Para que o script possa ser executado pelo nome ./file
, é necessário a permissão de execução no arquivo. chmod
é o comando usado para alterar permissões e +x
adiciona direitos de execução ao script.
chmod +x hello-world
Também é necessário adicionar o hashbang (#!) na parte superior do script. No Unix, arquivos com o hashbang
é interpretado como um executável.
Para confirmar onde o intérprete está localizado:
which bash
# Output: /usr/bin/bash
Então adicionamos #!/bin/bash
no início do script:
#!/bin/bash
echo "Hello, world!"
Você também pode ver
#!/usr/bin/env bash
, que pode ser usado se você não souber o caminho exato para o bash.
Feito isso, hello-world
pode ser executado diretamente:
./hello-world
# Output: Hello, world!
Para executar um script bash sem especificar o diretório (usando
./
, por exemplo), você deverá adicionar o diretório do script ao PATH executandoexport PATH=$PATH:/path/to/script/directory
. No entanto, isso geralmente não é necessário para scripts pessoais.
Strings
Uma sequência de caracteres simples que no bash não requer aspas, como normalmente vimos em linguagens de programação:
echo My String
# Output: My String
Para usar aspas em strings é necessário o uso do escape \
:
echo I\'m a string
# Output: I'm a string
Também podemos envolver a string em aspas duplas ou simples para omitir o uso de \
:
echo "I'm a string" # I'm a string
echo 'A simple "string" here' # A simple "string" here
Com a flag -e
, o bash iterpretará strings com caracteres de escape, como por exemplo o \n
para pular uma linha. Isso requer a string entre aspas:
echo -e "This string has a \nnew line"
# Output:
# This string has a
# new line
As strings entre aspas duplas também são importantes para uso com variáveis, como veremos na próxima seção.
Variáveis
Podemos usar variáveis como em qualquer linguagem de programação. Não há tipos de dados. Uma variável no bash pode conter um número, um caractere ou uma sequência de caracteres.
Também não é necessário declarar a variável, apenas atribuir um valor irá cria-la:
STR="Hello, My First Var!"
echo $STR
# Output: Hello, My First Var!
Nota: Observe que não deve haver espaços entre o sinal de igual e o nome e o valor da variável.
Cadeias de caracteres entre aspas duplas são necessárias para interpolar variáveis. Entre aspas simples, o cifrão seria interpretado literalmente:
WHO="Maicon"
echo 'Hello, $WHO' # Hello, $WHO
echo "Hello, $WHO" # Hello, Maicon
echo "Hello, ${WHO}" # Hello, Maicon
Essa sintaxe é necessária para qualquer coisa mais complexa que possamos fazer com uma variável, como obter um item de uma matriz, cálculos, condicionais, escopos etc.
Matrizes
Uma matriz no bash é definida entre parênteses e não há virgulas entre seus itens:
games=('TLOU 2', 'God of War', 'Gost of Tushima')
E para acessarmos dados de uma matriz, usa-se colchetes []
. As matrizes são indexadas em 0
:
echo ${games[0]} # TLOU 2
echo ${games[2]} # Gost of Tushima
Nota: para imprimir ou recuperar dados de matrizes, também é necessário o uso de
{}
.
Execução shell
Podemos atribuir a saída de um comando em tempo de execução adicionando $()
em torno do comando. Ex, para atribuir a data atual no formato dd-mm-yy hh:mm
em um uma variável no nosso script, ficaria VAR=$(date +"%d-%m-%y %H:%M")
:
DATE_NOW=$(date +"%d-%m-%y %H:%M")
echo $DATE_NOW
# Output: 25-06-20 16:50
Observer que o valor de DATE_NOW
é a saída do nosso comando em $(COMANDO)
.
Entrada do usuário
Já vimos como atribuir valores a uma variável via script, mas também podemos solicitar ao usuário esse valor via CLI. Isso é feito pelo comando read
:
echo 'Who are you?'
read who
echo "Hello, $who!"
# Output: Who are you?
# > Maicon
# Hello, maicon!
Operadores de comparação
Os operadores de comparação em scripts bash pode ser um pouco diferente se comparados a linguagens de programação como o JavaScript.
Por exemplo, é diferente quando comparamos números e quando comparamos cadeias de caracteres.
Aqui vai uma tabela com alguns exemplos:
Números | Strings | Descrição |
---|---|---|
-eq |
== |
Igual |
-ne |
!= |
Não igual |
-gt |
> |
Maior que |
-ge |
>= |
Maior ou igual |
-lt |
< |
Menor |
-le |
<= |
Menor ou igual |
Támbém é possível usar -z
para testar o vazio em uma sequência de caracteres.
Condições - Comandos de seleção ou de tomada de decisão
Em diversos momentos, um script precisa tomar uma ação baseado em alguma condição, um if else
.
A estrutura condicional de um bash é if
, test ou [ CONDICAO ]
, then
, else
, e fi
para finalizar o bloco.
Em CONDICAO
, é possível utilizar os operadores que vimos na tabela da seção anterior:
if [ CONDICAO ];
then
AÇÕES
fi
CONDICAO
: Avalia a condição passada, se verdadeiro executa a instrução do blocothen
;ELSE
: É executado quando [ CONDICAO ] não for verdadeira;AÇÕES
: Comandos que vão executar dentro do bloco;
Nota: Para fechar um if é necessário
fi
no final do bloco
Os colchetes '[ CONDICAO ]' são um atalho para o comando test. também poderia ser escrito "if test CONDICAO"
Vamos ao exemplo, um script que mostra se a idade passada no console é de uma pessoa maior ou menor de idade:
#!/bin/bash
echo "Qual sua idade?"
read age
if [ $age -gt 17 ]
then
echo 'Maior de idade'
else
echo 'Menor de idade'
fi
Elif - else if?
Em alguns casos é necessário testar mais de uma condição, todas correlacionadas. Para isso temos o elif
:
if [ CONDICAO_1 ];
then
AÇÕES_1
elif [ CONDICAO_2 ];
then
AÇÕES_2
elif [ CONDICAO_3 ];
then
AÇÕES_3
.
.
.
elif [ CONDICAO_N ];
then
AÇÕES_N
fi
Para ficar mais claro, vamos usar em um exemplo prático.
Vamos apresentar um menu para o usuário escolher uma opção. Baseado nesta escolha, a hora e a data serão exibidas; uma divisão será efetuada e seu resultado será exibido, e uma mensagem será exibida com o nome que o usuário fornecer:
#!/bin/bash
echo "Selecione uma opção:"
echo "1 - Exibir data e hora do sistema"
echo "2 - Exibir o resultado da divisão 10/2"
echo "3 - Exibir uma mensagem"
read opcao;
if [ $opcao -eq 1 ]
then
data=$(date +"%d-%m-%y %H:%M")
echo "$data"
elif [ $opcao -eq 2 ]
then
result=$((10/2))
echo "divisao de 10/2 = $result"
elif [ $opcao -eq 3 ]
then
echo "Qual seu nome?"
read name
echo "Bem-vindo ao shell script, $name"
fi
Case
O comando case
tem a mesma funcionalidade do if...then...elif
, com a diferença de sua sintaxe ser mais compacta e enxuta:
case VARIAVEL in
CASO_1)
AÇÕES_1
;;
CASO_2)
AÇÕES_2
;;
CASO_N)
AÇÕES_N
;;
esac
Para efeitos de comparação, vamos modificar o script visto em elif
para usar o case
:
#!/bin/bash
echo "Selecione uma opção:"
echo "1 - Exibir data e hora do sistema"
echo "2 - Exibir o resultado da divisão 10/2"
echo "3 - Exibir uma mensagem"
read opcao
case $opcao in
1)
data=$(date +"%d-%m-%y %H:%M")
echo "$data"
;;
2)
result=$((10/2))
echo "divisao de 10/2 = $result"
;;
3)
echo "Qual seu nome?"
read name
echo "Bem-vindo ao shell script, $name"
;;
esac
Loops
O uso de loops é muito comum quando precisamos iterar sobre um determinado valor até alguma condição seja satisfeita ou que o laço chegue ao fim.
O Bash usa os loops for
, while
e until
.
for VARIAVEL in VALOR_1, VALOR_2 … VALOR_N;
do
AÇÕES
done
VARIAVEL
: Variável cujo valor será inicializado e incrementado, respeitando os limites dos valores do conjunto fornecido;VALOR_1, VALOR_2, VALOR_N
: valores queVARIAVEL
poderá assumir durante oloop
;AÇÕES
: Ações a serem tomadas dentro doloop
.
Nota: A sequência
VALOR_1, VALOR_2, VALOR_N
pode ser substituida por{VALOR_1..VALOR_N}
.
Por exemplo, podemos utilizar o for..in
para listar todas as pastas em algum diretório do sistema:
echo -e "Testando a listagem de pastas"
files=~/folder/subfolder/*
for file in $files
do
echo $(basename $file)
done
A saída do script é o nome de cada pasta presente no diretório informado em files
.
While
Um outro exemplo bem comum é o uso do while..do
, que executa uma ação até que a condição de saída seja atendida:
echo "Informe o que você quiser, -1 para sair"
read dado;
while [ $dado != "-1" ];
do
echo “Você digitou $dado”
read dado;
done
O bloco do
será executado enquanto o valor imputado pelo usuário for diferente de -1
.
Funções
Funções são usadas para organizar estruturas lógicas, e no shell script não é diferente.
Para criar uma função é bem simples, basta:
nome_funcao() {
AÇÕES
}
Um exemplo bem básico onde o usuário pode optar por qual função chamar:
#!/bin/bash
main() {
echo "Escolha uma opção:"
echo "1 - Printar nome"
echo "2 - Printar idade"
read opcao
case $opcao in
"1")
print_name
;;
"2")
print_age
;;
esac
}
print_name() {
echo "Qual seu nome?"
read name
echo "Seu nome é $name"
}
print_age() {
echo "Qual sua idade?"
read age
echo "Sua idade é $age"
}
main
Nota: Lembre-se sempre de chamar a função principal (no nosso caso, main) no final do script, do contrário, nada acontecerá quando o script for executado.
Argumentos
Argumentos são muito comuns como dados de entrada em um programa.
O shell script tem alguns nomes especiais para argumentos recebidos por um script:
$0
: Contém o nome do script que foi executado;$1 --- $n
: Contém os argumentos na ordem em que foram passados (1º argumento em $1, 2º argumento em $2, etc.).$#
: Contém o número de argumentos que foi passado (ou seja, não considera o nome do script em $0);$*
: Retorna todos os argumentos de uma única vez.
Por exemplo:
#!/bin/bash
if [ $# -lt 1 ];
then
echo "Precisa fornecer pelo menos 1 argumento!"
exit 1
fi
echo "Número de argumentos passados: $#"
i=0
for argumento in $*
do
i=$(($i+1))
echo "Argumento $i passado: $argumento"
done
O script acima pede que pelo menos um argumento seja passado:
bash arguments Maicon
# Output:
# Número de argumentos passados: 1
# Argumento 1 passado: Maicon
Conclusão
Nesse artigo vimos o necessário para criar e executar um shell script. Com isso já é possível começar a criar scripts mais avançados para automatizar tarefas, rotinas etc.
Com shell scripts podemos instalar programas, realizar backups, executar tarefas etc. Aqui tem uma infinidade de possibilidades.
Um caso de uso bem legal é criar um script para preparar seu ambiente, e não ter que ficar instalando e configurando a máquina sempre que precisar formatar.
Você pode conferir o código produzido durante a escrita do artigo no meu Github.