Argumentos em scripts: $1, $2 e shift
1. Fundamentos dos Argumentos Posicionais
Quando você executa um script Bash, pode passar informações adicionais na linha de comando. Essas informações são chamadas de argumentos posicionais e são acessadas através das variáveis especiais $1, $2, $3 e assim por diante. O $1 representa o primeiro argumento, $2 o segundo, e assim sucessivamente até $N.
#!/bin/bash
# script: mostrar_args.sh
echo "Nome do script: $0"
echo "Primeiro argumento: $1"
echo "Segundo argumento: $2"
echo "Terceiro argumento: $3"
Execute com: ./mostrar_args.sh alfa beta gama
Nome do script: ./mostrar_args.sh
Primeiro argumento: alfa
Segundo argumento: beta
Terceiro argumento: gama
A variável $0 é especial: ela contém o nome do script (ou do shell) em execução. Diferente das variáveis de ambiente, que existem no contexto do shell como um todo, os argumentos posicionais são locais ao script e dependem exclusivamente do que foi digitado na linha de comando no momento da execução.
2. Navegando pelos Argumentos com $# e $@
Para trabalhar eficientemente com argumentos, o Bash oferece duas variáveis especiais adicionais:
$#: contém o número total de argumentos passados (excluindo$0).$@: representa todos os argumentos como uma lista separada, preservando espaços internos.
#!/bin/bash
echo "Total de argumentos: $#"
echo "Argumentos: $@"
A diferença entre $@ e $* é sutil, mas crucial:
#!/bin/bash
# teste_aspas.sh
echo "Com \$@:"
for arg in "$@"; do
echo " [$arg]"
done
echo "Com \$*:"
for arg in $*; do
echo " [$arg]"
done
Execute: ./teste_aspas.sh "João Silva" "Maria"
Com $@:
[João Silva]
[Maria]
Com $*:
[João]
[Silva]
[Maria]
Sempre use "$@" com aspas duplas para preservar argumentos com espaços. $* sem aspas quebra cada palavra separadamente.
3. O Comando shift: Removendo o Primeiro Argumento
O comando shift é uma ferramenta poderosa para manipular argumentos posicionais. Quando executado, ele descarta $1 e move todos os argumentos uma posição para a esquerda: o antigo $2 torna-se $1, $3 torna-se $2, e assim por diante.
#!/bin/bash
echo "Antes do shift: $1 $2 $3"
shift
echo "Depois do shift: $1 $2 $3"
Execute: ./shift_simples.sh um dois tres
Antes do shift: um dois tres
Depois do shift: dois tres
A sintaxe avançada shift N permite descartar múltiplos argumentos de uma só vez:
#!/bin/bash
echo "Antes: $1 $2 $3 $4"
shift 2
echo "Depois: $1 $2 $3 $4"
Execute: ./shift_multiplo.sh a b c d
Antes: a b c d
Depois: c d
Quando não há mais argumentos para deslocar, shift retorna um código de saída 1 (falha), mas não interrompe o script automaticamente. Por isso, é recomendável verificar $# antes de usar shift em loops.
4. Iterando sobre Argumentos com Loops e shift
O uso combinado de shift com loops while é uma técnica clássica para processar argumentos sequencialmente:
#!/bin/bash
# soma.sh - Soma todos os números fornecidos
soma=0
while [ $# -gt 0 ]; do
soma=$((soma + $1))
shift
done
echo "Soma total: $soma"
Execute: ./soma.sh 5 10 15
Soma total: 30
Alternativamente, o loop for com "$@" oferece uma abordagem mais limpa quando não precisamos modificar os argumentos:
#!/bin/bash
soma=0
for num in "$@"; do
soma=$((soma + num))
done
echo "Soma total: $soma"
A escolha entre while com shift e for com "$@" depende do contexto: use shift quando precisar consumir argumentos em pares (ex.: --nome valor) ou quando a ordem de processamento exigir descartes seletivos.
5. Tratamento de Opções e Flags Simples
Combinando case, $1 e shift, podemos interpretar flags como -v (verbose) ou --help:
#!/bin/bash
# backup.sh - Script de backup com opções
verbose=0
destino="./backup"
while [ $# -gt 0 ]; do
case "$1" in
-v|--verbose)
verbose=1
shift
;;
-d|--destino)
destino="$2"
shift 2
;;
-h|--help)
echo "Uso: $0 [-v] [-d DIR] arquivos..."
exit 0
;;
*)
break # Sai do loop, argumentos restantes são arquivos
;;
esac
done
echo "Modo verbose: $verbose"
echo "Diretório destino: $destino"
echo "Arquivos: $@"
Execute: ./backup.sh -v -d /tmp/backup doc1.txt doc2.txt
Modo verbose: 1
Diretório destino: /tmp/backup
Arquivos: doc1.txt doc2.txt
Armadilha comum: opções agrupadas como -abc não são interpretadas automaticamente. Para isso, seria necessário um parser mais sofisticado (como getopts).
6. Validação e Boas Práticas com Argumentos
Sempre valide se os argumentos obrigatórios foram fornecidos:
#!/bin/bash
usage() {
echo "Uso: $0 <nome_arquivo> <diretorio_destino>"
echo "Exemplo: $0 relatorio.pdf /tmp/backup"
exit 1
}
if [ $# -lt 2 ]; then
usage
fi
arquivo="$1"
destino="$2"
echo "Copiando $arquivo para $destino..."
Boas práticas adicionais:
- Use aspas duplas em "$1", "$2" e "$@" para preservar espaços.
- Defina uma função usage() clara para orientar o usuário.
- Evite assumir ordem fixa: documente ou use flags nomeadas.
- Verifique $# antes de acessar qualquer argumento posicional.
7. Argumentos com Espaços e Caracteres Especiais
Arquivos com espaços ou caracteres especiais exigem atenção redobrada:
#!/bin/bash
# processa_arquivos.sh
echo "Processando arquivos:"
for arquivo in "$@"; do
if [ -f "$arquivo" ]; then
echo " OK: $arquivo"
else
echo " ERRO: $arquivo não encontrado"
fi
done
Execute: ./processa_arquivos.sh "meu arquivo.txt" "outro arquivo.pdf"
Processando arquivos:
OK: meu arquivo.txt
OK: outro arquivo.pdf
Sem as aspas duplas, cada espaço quebraria o nome do arquivo em argumentos separados. Caracteres como * e ? também são seguros quando protegidos por aspas, evitando expansão prematura de globs.
8. Exemplos Práticos e Casos de Uso
Script de saudação personalizada:
#!/bin/bash
# saudacao.sh
if [ $# -lt 2 ]; then
echo "Uso: $0 <nome> <mensagem>"
exit 1
fi
echo "Olá $1! $2"
Execute: ./saudacao.sh "Maria" "Bem-vinda ao curso"
Olá Maria! Bem-vinda ao curso
Script de renomeação em lote:
#!/bin/bash
# renomear.sh
prefixo="$1"
shift
for arquivo in "$@"; do
mv "$arquivo" "${prefixo}_${arquivo}"
echo "Renomeado: $arquivo -> ${prefixo}_${arquivo}"
done
Execute: ./renomear.sh "foto" "praia.jpg" "cachorro.jpg"
Renomeado: praia.jpg -> foto_praia.jpg
Renomeado: cachorro.jpg -> foto_cachorro.jpg
Script de calculadora simples:
#!/bin/bash
# calc.sh
if [ $# -ne 3 ]; then
echo "Uso: $0 <operacao> <num1> <num2>"
echo "Operações: add, sub, mul, div"
exit 1
fi
op="$1"
n1="$2"
n2="$3"
case "$op" in
add) echo $((n1 + n2)) ;;
sub) echo $((n1 - n2)) ;;
mul) echo $((n1 * n2)) ;;
div)
if [ "$n2" -eq 0 ]; then
echo "Erro: divisão por zero"
exit 1
fi
echo $((n1 / n2))
;;
*) echo "Operação inválida: $op"; exit 1 ;;
esac
Execute: ./calc.sh add 10 20
30
Dominar $1, $2, $@ e shift é essencial para criar scripts Bash flexíveis e profissionais. Esses mecanismos permitem que seus scripts interajam dinamicamente com o usuário, processem listas de arquivos, interpretem flags de configuração e se adaptem a diferentes cenários de uso. Pratique combinando validação, loops e tratamento cuidadoso de espaços para construir ferramentas de linha de comando robustas e reutilizáveis.
Referências
- Bash Reference Manual: Positional Parameters — Documentação oficial GNU sobre parâmetros posicionais em Bash, incluindo
$1,$@e$*. - Advanced Bash-Scripting Guide: Shift Command — Guia avançado com explicações detalhadas e exemplos do comando
shifte suas variações. - Bash Hackers Wiki: Positional Parameters — Wiki colaborativa com dicas práticas sobre manipulação de argumentos posicionais e boas práticas.
- Linuxize: How to Use Command Line Arguments in Bash Scripts — Tutorial prático cobrindo
$1,$@,$#eshiftcom exemplos reais. - Shell Scripting Tutorial: Positional Parameters — Tutorial introdutório focado em argumentos posicionais, com exercícios e casos de uso comuns.
- Stack Overflow: What is the difference between $@ and $* in shell scripts? — Discussão técnica detalhada sobre a diferença entre
$@e$*com exemplos práticos.