Saltar para o conteúdo

Shell script

Origem: Wikipédia, a enciclopédia livre.
Bash - linha de comando

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.

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

[editar | editar código-fonte]

Selecionar Shell

[editar | editar código-fonte]

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:

#!/bin/sh

- 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:

#!/usr/bin/env bash

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

#Comentário
#- Segundo comentário
# // [ Terceiro comentário ] //

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:

MENSAGEM_DATA=1979
MENSAGEM_NOME="Bourne Shell"
mensagem_tipo1="Unix Shell"
mensagem_autor="Stephen Bourne"
MENSAGEM=ola
_MENSAGEM2=oi-2.020

Variáveis Pré-definidas

[editar | editar código-fonte]

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

[editar | editar código-fonte]

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:

VARIAVEL1=Teste
export VARIAVEL1
# Define e exporta com export
export VARIAVEL2=Teste

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

#!/usr/bin/env bash
meu_array=(1 2 3 4 5 6 7 8 9)
meu_Array=("abc" "def" "ghi")

Array Associativo

[editar | editar código-fonte]

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

#!/usr/bin/env bash
declare -A dicionario
dicionario["Brasil"]="Brasília"
dicionario["Goiás"]="Goiânia"
dicionário["São Paulo"]="São Paulo"
dicionario[Sergipe]=Aracajú
echo ${dicionario["Brasil"]}

Chamar variáveis

[editar | editar código-fonte]

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:

read -p "Digite um nome: " myname
echo "${myname:=$(whoami)}"

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
[editar | editar código-fonte]

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.

unset VAR
unset VAR1 VAR2 VAR3 VAR4

Declaração if para scripts em bash ou sh:

if [ $1 = $2 ]; then
    echo "Parametro 1=$1 é igual a 2=$2."
fi

Existe também outra forma:

[ $1 = $2 ] && { echo "Parametro 1 ($1) é igual a 2 ($2)."; exit 0; }

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:

if [ $1 = $2 ]; then
    echo "Parametro 1 ($1) é igual a 2 ($2)."
else
    echo "Parametro 1 ($1) não é igual a 2 ($2)."
fi

Mas, existe uma abreviação que também é muito utilizada que é menor e muito boa para teste de linha única:

[ $1 = $2 ] && { echo "Parametro 1 ($1) é igual a 2 ($2)."; exit 0; } || { echo "Parametro 1 ($1) é diferente de 2 ($2)."; exit 0; }

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

if [ $3 ]; then
    echo "$3"
elif [ $2 ]; then
    echo "$2"
else
    echo "$1"
fi

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

case "$var" in
    valor)
    ;;
esac

Expressões Regulares

[editar | editar código-fonte]

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

#!/usr/bin/env bash
[[ $1 =~ ^sh|SH$ ]] && { echo "$1 - Bourne Shell"; }

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

[editar | editar código-fonte]
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

[editar | editar código-fonte]
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

[editar | editar código-fonte]
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

[editar | editar código-fonte]
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

[editar | editar código-fonte]
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 ]

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

# Irá executar echo "Test" 3 vezes
for i in 1 2 3
do
    echo "Test"
done
# Em apenas uma linha
for i in 1 2 3; do echo "Test"; done

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

while [ -z $a_input ]; do
    read -p "Enter para continuar ou digite qualquer coisa para sair: " a_input
done

while [ -z $b_input ]; do read -p "Enter para continuar ou digite qualquer coisa para sair: " b_input; done

while read -p "Digite um numero: " c_input
do
    if [ $c_input -gt 25 ]; then
        echo "Numero $c_input é maior que 25"
        break
    else
        echo "Numero $c_input é menor que 25"
        break
    fi
done

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:

# Ambos aceitam esse formato
minha_função(){
    echo
}
# Esse formato apenas Bash aceitará
function minha_função(){
    echo
}

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:

nova_função() {
    echo "Olá, Mundo!"
}
nova_função

Status de saída

[editar | editar código-fonte]

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:

[ ! -e /bin/bash ] && { exit 2; }

O próximo exemplo irá checar se um comando não foi executado com sucesso:

ping -c1 wikipedia..org
[ $? -ne 0 ] && echo "O comando ping emitiu algum erro."

Os script passados acima são para exemplos de implementação..

Exemplos de uso

[editar | editar código-fonte]

Criar Shell script

[editar | editar código-fonte]

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:

echo '#!/usr/bin/env bash' > novo_script.sh

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

[editar | editar código-fonte]

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:

while [ $# -gt 0 ]; do
    case "$1" in
        version | -v) echo "Release v0.1.0 - from Wikipedia.org";;
        *) echo "$0: Este parâmetro '$1' não foi reconhecido, saindo...";exit 1;;
    esac
    shift
done

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

[editar | editar código-fonte]

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

#!/usr/bin/env bash
cd /tmp
find . -type f -mtime +30 -delete

Ligações externas

[editar | editar código-fonte]
Outros projetos Wikimedia também contêm material sobre este tema:
Wikilivros Livros e manuais no Wikilivros