Fundamentos de Shell Scripting - Variáveis, Condicionais, Loops, test

Fundamentos de Shell Scripting - Variáveis, Condicionais, Loops, test

O Que Você Vai Conquistar

  • Explicar o papel do shebang (#!/bin/bash) e tornar um script executável
  • Usar variáveis, parâmetros posicionais, parâmetros especiais e substituição de comandos corretamente
  • Testar strings, números e arquivos com test / [ ] / [[ ]]
  • Escrever estruturas de controle com if / case / for / while / until
  • Escolher entre exit status e exit / && / ||, e funções de shell

Este é o núcleo do objetivo 105.2 do LPIC-1 "Personalizar ou escrever scripts simples" (LPIC 102). É a menor unidade de técnica para automatizar operações diárias.

Qual é a Estrutura Básica de um Shell Script?

Um shell script consiste em "shebang -> definições de variáveis -> corpo do processamento". O shebang na primeira linha determina o interpretador, e uma vez concedida a permissão de execução com chmod +x, você pode executá-lo com ./script.sh.

Elemento Sintaxe Função
Shebang #!/bin/bash Especificar o interpretador a executar
Variável name=value Armazenar um valor (sem espaços ao redor do =)
Referência $name / ${name} Expandir o valor da variável
Substituição de cmd $(command) Obter saída de comando como valor
Saída exit N Sair com status N

O kernel interpreta o shebang quando os dois primeiros bytes de um script são #!. #!/bin/bash executa sob bash, e #!/bin/sh executa sob um shell POSIX. Este é o método padrão de invocação definido na seção "INVOCATION" do man bash.

O shebang deve estar no início da primeira linha. Se uma linha em branco ou espaço o preceder, ele será tratado como um comentário comum e não terá efeito.

Passos

Passo 1: Escrever o shebang e tornar executável

cat > hello.sh <<'EOF'
#!/bin/bash
echo "Hello, LPIC"
EOF
chmod +x hello.sh
./hello.sh
Hello, LPIC

A primeira linha #!/bin/bash especifica o interpretador. Conceda permissão de execução com chmod +x e execute com ./hello.sh. Passar o script explicitamente ao interpretador como bash hello.sh não requer permissão de execução nem shebang, mas na prática é convencional definir ambos.

Passo 2: Usar variáveis e aspas

#!/bin/bash
name="Penguin Gym"
count=3
echo "${name} : ${count}"
echo "${name}_log"
Penguin Gym : 3
Penguin Gym_log

A atribuição usa a forma name="value", e você não deve colocar espaços ao redor do =. Ao referenciar, envolver em chaves como ${name} torna o limite do nome da variável claro mesmo quando caracteres seguem imediatamente, como em ${name}_log. Note as aspas duplas "..." porque o valor contém um espaço.

Passo 3: Ler parâmetros posicionais e especiais

#!/bin/bash
echo "Script name: $0"
echo "First argument: $1"
echo "Argument count: $#"
echo "All arguments: $@"
Script name: ./args.sh
First argument: alpha
Argument count: 2
All arguments: alpha beta

$0 é o nome do script, e $1 até $9 são os argumentos em ordem. $# é o número de argumentos, e $@ e $* representam todos os argumentos. A diferença é que "$@" expande cada argumento como uma string separada, enquanto "$*" expande como uma única string (man bash "Special Parameters"). Para iterar sobre argumentos, use "$@".

Variável Significado
$0 Nome do script
$1 a $9 Parâmetros posicionais (enésimo argumento)
$# Número de argumentos
$@ / $* Todos os argumentos
$? Exit status do comando anterior
$$ PID do shell atual
$! PID do comando em background mais recente

Passo 4: Capturar saída em uma variável com substituição de comando

#!/bin/bash
today=$(date +%F)
files=$(ls /etc | wc -l)
echo "${today} : ${files} items in /etc"
2026-05-30 : 152 items in /etc

$(command) expande a saída padrão de um comando como string. Isso é a substituição de comando. É equivalente à sintaxe mais antiga `command` (crase), mas $(...) é recomendada por facilitar aninhamento e leitura (man bash "Command Substitution").

Passo 5: Testar condições com test / [ ] / [[]]

#!/bin/bash
a="abc"; n=5
[ "$a" = "abc" ] && echo "string match"
[ "$n" -gt 3 ] && echo "number: greater than 3"
[ -f /etc/passwd ] && echo "file exists"
string match
number: greater than 3
file exists

[ ... ] é um alias para o comando test, e um espaço é obrigatório logo após [ e logo antes de ]. Use = e != para comparação de strings, -eq, -ne, -lt, -gt para comparação numérica, e -f (arquivo regular), -d (diretório), -e (existe), -r, -w, -x (permissão de leitura, escrita, execução) para testes de arquivo (man test). A extensão bash [[ ... ]] suprime word splitting e expansão de pathname e permite escrever &&, ||, <, > diretamente, sendo mais fácil de lidar quando você se limita ao bash.

Tipo Operadores Exemplo
String = / != [ "$a" = "$b" ]
Numérico -eq -ne -lt -gt -le -ge [ "$n" -eq 0 ]
Arquivo -f -d -e -r -w -x [ -d /tmp ]

Usar > ou < para comparação numérica dentro de [ ] é interpretado como "redirecionamento" ou "comparação lexicográfica de string" e produz resultados inesperados. Sempre use -gt / -lt e similares para comparação numérica.

Passo 6: Ramificar com if / case

#!/bin/bash
score=$1
if [ "$score" -ge 80 ]; then
    echo "pass"
elif [ "$score" -ge 60 ]; then
    echo "review"
else
    echo "fail"
fi
pass

A forma básica é if condition; then ... elif condition; then ... else ... fi. O ponto crucial é que if ramifica com base no exit status 0 (verdadeiro) do comando de condição. Para ramificar por um conjunto de valores, case é mais legível.

#!/bin/bash
case "$1" in
    start) echo "starting" ;;
    stop)  echo "stopping" ;;
    *)     echo "usage: $0 {start|stop}" ;;
esac
starting

A forma é case value in pattern) action ;; esac. Cada ramo termina com ;;, e *) captura "nenhuma das opções acima". Esse é o padrão clássico para scripts de inicialização de serviços.

Passo 7: Repetir com for / while / until

#!/bin/bash
for f in *.log; do
    echo "processing: $f"
done

n=1
while [ "$n" -le 3 ]; do
    echo "count: $n"
    n=$((n + 1))
done
processing: access.log
processing: error.log
count: 1
count: 2
count: 3

for variable in value-list; do ... done processa uma lista em ordem. while condition; do ... done repete enquanto a condição for verdadeira, e until condition; do ... done repete inversamente até que a condição se torne verdadeira. $((...)) é a expansão aritmética, usada para cálculo inteiro (man bash "Arithmetic Expansion").

Passo 8: Receber entrada com read e sair com exit

#!/bin/bash
read -p "Enter your name: " who
if [ -z "$who" ]; then
    echo "name is empty" >&2
    exit 1
fi
echo "Welcome ${who}"
exit 0
Enter your name: rina
Welcome rina

read variable lê uma linha da entrada padrão para uma variável (-p exibe um prompt). exit N encerra o script com exit status N. Por convenção, 0 é sucesso e 1 ou mais é falha. [ -z "$who" ] testa se a string está vazia.

Como Usar Exit Status e && / ||

O exit status do comando anterior é armazenado em $?. 0 é sucesso e diferente de zero é falha. Usando esse valor, você pode encadear comandos com && (executa o próximo se o anterior teve sucesso) e || (executa o próximo se o anterior falhou).

mkdir -p /tmp/work && echo "created" || echo "failed"
echo "$?"
created
0

A && B executa B apenas quando o exit status de A é 0. A || B executa B apenas quando A é diferente de zero. O teste do if também é baseado nesse exit status, e quando você entende a definição de verdade específica do shell onde "verdadeiro = exit status 0", o comportamento da ramificação condicional parece consistente.

Você também pode agrupar processamento em uma função de shell. Dentro de uma função, return N define o exit status da função, enquanto exit N encerra o script inteiro.

#!/bin/bash
greet() {
    echo "Hello, $1"
    return 0
}
greet "world"
echo "function return value: $?"
Hello, world
function return value: 0

Defina uma função com name() { ... } e chame-a com name arguments. Dentro da função, argumentos também são referenciados com $1, $2, $#, porque os parâmetros posicionais alternam por chamada. Quando return é omitido, o exit status do último comando executado na função é retornado.

Erros Comuns e Correções

Erro Sintoma Forma correta
Espaços ao redor de = na atribuição var: command not found var=value (sem espaços)
Falta de aspas Argumentos divididos em valores com espaços Envolva em aspas duplas, como [ "$var" = "x" ]
Espaços faltando em [ ] [: missing ']' [ "$a" = "$b" ] (espaço após [ e antes de ])
Usar = / > para comparação numérica Lido como comparação de string ou redirecionamento Use -eq / -gt para números
Interpretar mal o exit status if se comporta ao contrário Entenda que verdadeiro significa "exit status 0"

Um erro particularmente comum é o espaço na atribuição. Se você escrever var = value, o shell interpreta var como o nome do comando e = e value como argumentos, tenta executá-lo e reporta command not found.

Solução de Problemas

Sintoma: O script não inicia com "Permission denied"

Causa: Sem permissão de execução, ou shebang inválido

Verificação:

ls -l script.sh
head -n 1 script.sh

Correção: Conceda permissão de execução com chmod +x script.sh. Confirme também que o shebang está na primeira linha sem linha em branco antes. Como alternativa, você pode executá-lo diretamente com bash script.sh.

Sintoma: Atribuição de variável reporta "command not found"

Causa: Há espaços ao redor do =

Verificação:

bash -n script.sh

Correção: Remova os espaços, como em var=value. bash -n pode ser usado para verificação de sintaxe (verifica apenas a gramática, sem executar).

Sintoma: Ramificação condicional quebra quando um valor contém espaços

Causa: A referência da variável não está entre aspas, então ocorre word splitting

Verificação:

bash -x script.sh

Correção: Envolva a variável em aspas duplas, como [ "$var" = "value" ]. bash -x exibe o resultado expandido de cada comando, para que você possa identificar onde a divisão ocorre.

Lista de Verificação

  • [ ] Escreveu o shebang (#!/bin/bash) na primeira linha
  • [ ] Concedeu permissão de execução com chmod +x
  • [ ] Confirmou que não há espaços ao redor do = nas atribuições
  • [ ] Colocou aspas nas referências de variável como "$var"
  • [ ] Verificou os espaços dentro de [ ] e os operadores de comparação (string vs numérico)
  • [ ] Retornou um exit status com exit 0 / exit 1

Resumo

Cenário Sintaxe Finalidade
Primeira linha #!/bin/bash Especificar o interpretador
Obter valor $(command) Transformar saída de comando em variável
Teste string [ "$a" = "$b" ] Igual / diferente
Teste numérico [ "$n" -gt 3 ] Comparação de magnitude
Ramificação if / case Ramificar por condição ou valor
Repetição for / while / until Processamento em loop
Encadeamento A && B / A || B Encadear por exit status

Shell scripting é a base da automação de operações Linux. Após cobrir 105.2, combine com variáveis de ambiente (105.1) e comandos de processamento de texto e expressões regulares para escrever scripts de automação práticos.

Próximas Leituras

Continue Sua Jornada LPIC-1

Hub LPIC-1

  • Hub de Aprendizado LPIC-1 -- Mapa completo de artigos LPIC-1, acompanhamento de progresso e cobertura dos objetivos do exame

Artigos LPIC-1 Relacionados

Prática