você está aqui: Home  → Arquivo de Mensagens

Maus hábitos em bash

Colaboração: Rubens Queiroz de Almeida

Data de Publicação: 28 de julho de 2010

Frequentemente, fazemos uso incorreto de comandos em bash. Não que faça muita diferença, mas não custa nada aprendermos algumas regrinhas, que tornarão o nosso código mais eficiente e legível.

Comando cat

Muitos de nós (eu inclusive) temos o hábito de fazer coisas como:

  cat arquivo.txt | wc -l

O comando cat significa catenate, que significa concatenar. Se eu tenho apenas um arquivo, não preciso do cat, posso usar o wc diretamente:

  wc -l arquivo.txt

Já se eu quisesse contar o número de linhas em diversos arquivos, eu poderia usar o cat com o comando wc:

  cat arquivo1.txt arquivo2.txt arquivo3.txt | wc -l

Mas tudo irá depender do que se quer fazer. O comando wc também pode ser usado com esta finalidade, mas a saída é ligeiramente diferente:

  $ wc -l /etc/passwd /etc/hosts
    39 /etc/passwd
    12 /etc/hosts
    51 total

Com o cat:

  $ cat /etc/passwd /etc/hosts | wc -l
  51

O comando wc é mais falante e se eu faço uso deste recurso em uma situação em que preciso apenas do número de linhas, esta verbosidade precisará ser tratada de alguma forma, o que é desnecessário.

Comando ls

Um erro bem comum:

  for arquivo in `ls *`
  do
   ...
  done

Eu não preciso usar o ls para obter uma listagem dos arquivos em um diretório neste trecho. Eu posso fazer assim:

  for arquivo in *
  do
   ...
  done

Uma outra variação desta prática, com o comando cat:

  cat `ls *`

Porque não fazer assim?

  cat *

Cuidado com o rm

Quem nunca fez algo assim?

  rm -rf ~/ *.trash

O que a pessoa queria? Remover de seu diretório pessoal todos os arquivos terminados em trash. O que aconteceu? Este infeliz removeu todo o seu diretório pessoal e apagou os arquivos terminados em trash do diretório corrente. O causador de tudo isto foi o espaço em branco entre ~/ e *.trash. A pressa é inimiga da perfeição :-(

Na verdade o que ele queria era:

  rm -rf ~/*.trash

while ou for?

Vejamos:

  for f in `cat arquivo.txt`
  do
    ...
  done

Podemos fazer também assim:

  while read f
  do
   ...
  done < arquivo.txt

Na primeira opção, o resultado do comando `cat arquivo.txt`, pode ser uma linha mais longa do que o seu sistema pode tratar, o que pode trazer resultados indesejáveis.

Referências

  • Useless Use of Cat Award - grande parte desta dica foi baseada nesta página. Leitura obrigatória, com diversos outros exemplos interessantes.
  • Useless use of cat
  • Shell Script Profissional - O livro Shell Script Profissional, de autoria do Aurélio Marinho Jargas, é referência obrigatória para quem deseja programar como gente grande :-) Vale cada centavo!


Veja a relação completa dos artigos de Rubens Queiroz de Almeida

 

 

Opinião dos Leitores

Saulo Gomes
09 Ago 2010, 11:41
Mais uma do vício dos pipes:

$cat /etc/passwd | less

pode ser usado diretamente:

$less /etc/passwd

O exemplo do "for + ls" também é muito usado pelos menos experientes.

Graças a esse post já não tenho mais esse mau habito.
rehab
02 Ago 2010, 21:58
Outro péssimo hábito em bash:

$ cd /pub
$ more beer
M.
30 Jul 2010, 14:40
haha adorei. Outra muito comum:
cat arquivo.txt | grep "palavra"

ao invés de apenas:
grep "palavra" arquivo.txt
Pedro Moura
28 Jul 2010, 22:06
Parabéns muito bom mesmo!
Márcio Pessoa
28 Jul 2010, 19:25
Excelente dicas Rubens.

É interessante testar essas dicas com o comando time, fica claro como os maus hábitos podem contribuir para um desempenho precário em scripts.


Valeu.
Sérgio Luiz Araújo Silva
28 Jul 2010, 08:29
Outro erro comun é usar o grep junto com o awk, quando em muitos casos o awk sozinho resolve:

awk -F":" '/user/ {print $1}' /etc/passwd
hermes (hdab)
28 Jul 2010, 01:32
legal a dica. o vício dos pipes é realmente um problema. o assunto acabou sendo pertinente por conta do que postei hoje no twitter:

por que o array v tem comportamento distinto nos dois laços?

cat foo | while read i; do v=(${v[*]} $i); done
for i in $(cat bar); do v=(${v[*]} $i); done

BASH_VERSION='4.1.5(1)-release'
*Nome:
Email:
Me notifique sobre novos comentários nessa página
Oculte meu email
*Texto:
 
  Para publicar seu comentário, digite o código contido na imagem acima
 


Powered by Scriptsmill Comments Script