Introdução ao Script Dash: Diferenças do Bash e Como Escrever para Compatibilidade
Você já teve a experiência de escrever um script de shell que funciona no seu PC, mas não no servidor? Talvez a causa seja a diferença entre Dash e Bash.
Neste artigo, explicaremos a sintaxe básica do Dash, o shell por trás do /bin/sh em muitos sistemas Linux (especialmente Debian e Ubuntu). Preparamos vários exemplos de código concretos para que até mesmo os iniciantes possam copiar, colar e ver que 'funciona!'. Também resumimos os pontos de atenção sobre a compatibilidade com o Bash, para que você possa adquirir as habilidades para escrever scripts mais robustos e portáteis.
Afinal, o que é Dash? Qual a diferença para o Bash?
O que costumamos chamar de "script de shell" geralmente se refere ao Bash (Bourne Again SHell). O Bash é muito poderoso e oferece muitas notações convenientes.
Por outro lado, o Dash (Debian Almquist SHell) é um shell mais simples e leve, compatível com o padrão POSIX. Por ser muito rápido, é adotado em sistemas operacionais como Debian e Ubuntu para scripts de inicialização do sistema e como o shell padrão (/bin/sh).
Isso significa que um script escrito com #!/bin/sh pode funcionar no seu PC (ambiente Bash), mas pode dar erro em um servidor (ambiente Dash). Para evitar isso, o caminho mais rápido é aprender a escrever de forma compatível com POSIX, que o Dash também pode interpretar.
Sintaxe Básica de Scripts Dash [Pode Copiar e Colar]
Primeiro, vamos nos familiarizar com a sintaxe básica do Dash. Todos os códigos começam com #!/bin/sh, então você pode simplesmente salvá-los em um arquivo e executá-los.
1. Olá, Mundo! - Saída de string
O clássico 'Olá, Mundo'. Usamos o comando echo para imprimir strings. Isso é exatamente igual ao Bash.
#!/bin/sh
# No início do script, escrevemos um 'shebang' para especificar em qual shell ele deve ser executado
echo "Hello, Dash World!"
2. Como usar variáveis
A regra é não colocar espaços ao redor do = ao definir uma variável. Para usá-la, coloque um $ antes do nome da variável. Isso também é igual no Bash.
#!/bin/sh
GREETING="Olá"
TARGET="Mundo"
echo "${GREETING}, ${TARGET}!" # É recomendável colocar os nomes das variáveis entre {} para maior clareza
3. Desvio condicional com 'if'
Para desvios condicionais, usamos a instrução if. A expressão condicional é colocada entre [ ... ]. Este é o primeiro ponto de atenção: o [[ ... ]], muito comum no Bash, não pode ser usado no Dash (explicaremos em detalhes mais tarde).
#!/bin/sh
USER_NAME="Alice"
# É necessário ter espaços antes e depois de [ ]
if [ "$USER_NAME" = "Alice" ]; then
echo "Bem-vinda, Alice."
else
echo "Quem é você?"
fi
4. Repetição com o laço 'for'
Vamos escrever um laço for simples usando uma lista separada por espaços.
#!/bin/sh
# Processar uma string separada por espaços com um laço
for fruit in apple banana cherry
do
echo "Eu gosto de ${fruit}."
done
[Mais Importante] Pontos a Observar para Compatibilidade com o Bash
Agora vamos ao que interessa. Recursos convenientes que são comuns no Bash podem causar erros no Dash. Vamos ver alguns exemplos típicos.
Diferença 1: Arrays
O Dash não suporta arrays. Esta é uma diferença muito significativa.
❌ A forma do Bash (não funciona no Dash)
#!/bin/sh
# Este código causará um erro no Dash!
fruits=("apple" "banana" "cherry")
echo "A primeira fruta é ${fruits[0]}."
⭕ Solução alternativa no Dash
Você pode obter um resultado semelhante usando strings separadas por espaços ou a lista de argumentos ($@).
#!/bin/sh
# Processamento de laço compatível com POSIX
fruit_list="apple banana cherry"
for fruit in $fruit_list
do
echo "Processando fruta: $fruit"
done
Diferença 2: Expressões condicionais [[ ... ]] vs [ ... ]
O Dash não consegue interpretar [[ ... ]]. Use sempre [ ... ] (que é uma forma abreviada do comando test) para expressões condicionais.
❌ A forma do Bash (não funciona no Dash)
O [[ é útil para comparação de strings e operadores lógicos (&&, ||), mas é uma extensão específica do Bash.
#!/bin/sh
# Este código causará um erro no Dash!
COUNT=10
if [[ "$USER" = "root" && $COUNT -gt 5 ]]; then
echo "Condição satisfeita."
fi
⭕ A forma do Dash (compatível com POSIX)
Use [ ... ] e represente o E lógico com -a e o OU lógico com -o.
#!/bin/sh
# Escrita com foco na compatibilidade
COUNT=10
# Para combinar múltiplas condições, use -a (AND) ou -o (OR)
if [ "$USER" = "root" -a $COUNT -gt 5 ]; then
echo "Condição satisfeita."
fi
Diferença 3: A palavra-chave function
No Dash, a palavra-chave function não pode ser usada. As funções são declaradas no formato nome_da_funcao() { ... }.
❌ A forma do Bash (não funciona no Dash)
#!/bin/sh
# Este código causará um erro no Dash!
function say_hello() {
echo "Hello from function!"
}
say_hello
⭕ A forma do Dash (compatível com POSIX)
Esta é a forma padrão mais antiga e, claro, também funciona no Bash.
#!/bin/sh
# Declaração de função compatível com POSIX
say_hello() {
echo "Olá! Chamado de uma função."
}
# Chamando a função
say_hello
Diferença 4: Substituição de processo <()
A substituição de processo <(), que permite tratar a saída de um comando como um arquivo, é um recurso do Bash.
❌ A forma do Bash (não funciona no Dash)
#!/bin/sh
# Este código causará um erro no Dash!
# O comando comm compara dois arquivos ordenados
comm <(ls -1 dir1) <(ls -1 dir2)
⭕ Solução alternativa no Dash
Salve a saída em um arquivo temporário primeiro ou processe-a usando um pipeline de forma inteligente.
#!/bin/sh
# Método usando arquivos temporários
TMP1="/tmp/dir1_list"
TMP2="/tmp/dir2_list"
ls -1 dir1 > "$TMP1"
ls -1 dir2 > "$TMP2"
comm "$TMP1" "$TMP2"
# Não se esqueça de limpar depois
rm "$TMP1" "$TMP2"
Diferença 5: Expansão de chaves {1..10}
A expansão de chaves, para gerar números ou strings sequenciais, é um recurso do Bash.
❌ A forma do Bash (não funciona no Dash)
#!/bin/sh
# No Dash, este código imprimirá literalmente a string {1..5}
echo "Criando arquivos arquivo{1..5}.txt"
touch file_{1..5}.txt
⭕ Solução alternativa no Dash
Para gerar uma sequência de números, use o clássico comando seq.
#!/bin/sh
# Combinar o comando seq com um laço for
echo "Criando arquivos sequenciais de 1 a 5"
for i in $(seq 1 5)
do
touch "file_${i}.txt"
echo "Arquivo número ${i} foi criado."
done
Exemplo Aplicado: Um Script Prático em Dash
Finalmente, vamos usar o que aprendemos para escrever um script um pouco mais prático. Este script move todos os arquivos .log do diretório atual para um diretório de backup com a data de hoje. E, claro, é compatível com o Dash.
#!/bin/sh
# Obter a data de hoje no formato AAAA-MM-DD
# Os especificadores de formato do comando date são padronizados no POSIX, então isso é seguro
BACKUP_DIR="backup_$(date +%Y-%m-%d)"
# Criar o diretório de backup se ele não existir
if [ ! -d "$BACKUP_DIR" ]; then
echo "Criando diretório de backup ${BACKUP_DIR}."
mkdir "$BACKUP_DIR"
fi
# Percorrer os arquivos .log em um laço
# A expansão de curinga para *.log é um recurso padrão do shell
for file in *.log
do
# Verificar se o arquivo existe e é um arquivo regular
if [ -f "$file" ]; then
echo "Movendo ${file} para ${BACKUP_DIR}/."
mv "$file" "$BACKUP_DIR/"
fi
done
echo "Backup concluído."
Resumo
Estar ciente das diferenças entre Dash e Bash e se esforçar para escrever código compatível com POSIX melhorará drasticamente a portabilidade de seus scripts. Pode parecer um pouco inconveniente no início, mas esse passo extra evitará erros inesperados devido a diferenças de ambiente e o deixará um passo mais perto de ser um 'programador competente'.
Os tópicos abordados aqui são básicos, mas extremamente importantes. Por favor, tente executar um script com #!/bin/sh em seu próprio ambiente. E sinta a tranquilidade de saber que seu script funcionará em qualquer lugar!