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"
fipass
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}" ;;
esacstarting
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))
doneprocessing: 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 0Enter 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.