test, [, and [[ (2020)

Programadores de shell avaliam os trade-offs entre `[ / test` padrão POSIX e `[[` específico do Bash para condicionais, destacando como regras sutis de sintaxe, armadilhas de aspas e peculiaridades da lógica booleana podem facilmente introduzir bugs. Muitos defendem manter-se em `sh` compatível com Bourne e portátil quando os scripts precisam rodar em sistemas diversos ou restritos (por exemplo, BSD, embarcados, imagens Docker mínimas), enquanto outros preferem recursos de Bash, zsh ou ksh pela conveniência em ambientes controlados. A conversa também se expande para saber se scripts shell complexos deveriam ser substituídos por linguagens “de verdade” como Python ou Perl, o papel de ferramentas como ShellCheck e `set -euo pipefail`, e como equilibrar portabilidade de longo prazo e produtividade do desenvolvedor.

Escolha do shell e portabilidade

  • Grande divisão entre “é só usar Bash/[[” e “mirar em POSIX sh”.
  • Lado pró-Bash: [[ é mais claro e poderoso; muitos ambientes que controlam já têm bash, zsh ou ksh. Instalar bash é visto como pouco esforço em muitos contextos.
  • Lado da portabilidade: bash nem sempre está presente (BSDs, sistemas embarcados, imagens Docker mínimas, configurações só com busybox, máquinas de clientes bloqueadas, macOS com bash antigo).
  • Escrever Bourne/POSIX sh é descrito como parte da maturidade profissional quando scripts rodam em sistemas desconhecidos ou legados.
  • Alguns argumentam que portabilidade tem um custo e não deveria ser um objetivo universal; para scripts internos, tudo bem depender de bashisms.

[, test e [[

  • [, test são POSIX e normalmente binários ou builtins; [[ é específico do shell (bash, zsh, ksh, etc.).
  • Vários preferem test em vez de [ para reforçar que é um comando, não sintaxe; o ] de fechamento do [ e a “sintaxe” parecida são vistos como gambiarras enganosas.
  • Outros dizem que [[ é preferível quando você já decidiu usar Bash, por causa de semântica mais segura (por exemplo, regex, correspondência por padrões, menos armadilhas de aspas).
  • Alguns insistem em usar apenas recursos POSIX mesmo quando os shells suportam [[; outros dizem que isso é mera “adoração da portabilidade”.

Armadilhas comuns e técnicas

  • A maior armadilha: variáveis sem aspas com test/[ (valores vazios ou com espaços, comportamento de argumento único). Conselho repetido: “coloque aspas nas variáveis” e use ferramentas como ShellCheck e set -euo pipefail.
  • Usar && / || como abreviação de if é popular, mas tem semântica diferente de falha quando o comando após o && falha.
  • -a / -o dentro de test são apontados como obsoletos; encadear testes separados com && / || é preferível.
  • Lógica booleana é estranha: não há um tipo booleano real; soluções alternativas usam códigos de saída ou 0/1 numéricos.

Quando usar shell vs outra linguagem

  • Vários argumentam que lógica complexa deveria ir para uma linguagem “de verdade” (Python, Perl, Node/zx, etc.); shell é melhor para cola, orquestração e testes de integração.
  • Outros defendem shell como uma “linguagem de verdade” se usado com disciplina, mas ainda assim não começariam projetos grandes nele.

Padrões, GNUismos e peculiaridades do ecossistema

  • Debate sobre manter-se em POSIX vs explorar extensões GNU/Bash (pipefail, flags do grep/sed GNU, etc.).
  • POSIX é visto como valioso para interoperabilidade, mas também como algo atrasado em relação às necessidades do mundo real.
  • Várias observações laterais: dash como /bin/sh no Debian/Ubuntu, macOS com ferramentas BSD vs GNU, tratamento especial de [] no autoconf, comportamentos estranhos de $_ e layouts de symlink vs hardlink no busybox.