você está aqui: Home  → Arquivo de Mensagens

Bash - Estruturas Básicas

Colaboração: Rodrigo Bernardo Pimentel

Data de Publicação: 16 de Agosto de 2000

É comum queremos executar a mesma função, ou uma função parecida, sobre uma série de argumentos, um por vez. Em bash, há duas estruturas básicas pra isso: "for" e "while".

O "for", em bash, é diferente do "for" em linguagens como C ou Perl. Nessas linguagens, o "for" é simplesmente um "while" mais completo. Em bash, o for atua sobre uma seqüência de parâmetros (não necessariamente numéricos ou seqüenciais). Por exemplo:

  [rbp@muppets ~]$ for i in 1 2 3 4 5; do echo $i; done=
  1
  2
  3
  4
  5
  [rbp@muppets ~]$ =

Ou,

  [root@muppets ~]$ for login in rbp sizinha queiroz; do adduser $login; done=
  [root@muppets ~]$ =

Você pode inclusive usar o for a partir de uma saída de comando. Por exemplo, digamos que você tenha um arquivo com uma série de nomes de usuários a serem acrescentados ao sistema, como no exemplo acima:

  [root@muppets ~]$ for login in ""cat /tmp/usuarios""; do adduser $login; done=
  [root@muppets ~]$ =

O "while", por sua vez, tem funcionamento semelhante à maioria das linguagens procedurais mais comuns. Um comando ou bloco de comandos continua a ser executado enquanto uma determinada condição for verdadeira. Por exemplo, imitando o exemplo acima:

  [rbp@muppets ~]$ while [ $i -le 5 ]; do echo $i; i=$(($i + 1)); done=
  1
  2
  3
  4
  5
  [rbp@muppets ~]$ =

Aos poucos:

  while [ $i -le 5 ]

O "while" deve ser seguido de "verdadeiro" ou "falso". Se for "verdadeiro", o bloco é executado e o teste é repetido. Se for falso, não.

No caso, "[ $i -le 5 ]" é uma forma de usarmos o comando "test". Esse comando testa uma expressão e retorna verdadeiro ou falso. Poderia ser escrito como

  while test $i -le 5

"$i -le 5" é a expressão testada. O programa "test" aceita alguns operadores. Entre eles:

  -lt (less than) - primeiro argumento é menor do que o segundo
  -le (less or equal) - primeiro argumento é menor ou igual ao segundo
  -gt (greater than) - primeiro argumento é maior do que o segundo
  -ge (greater or equal) - primeiro argumento é maior ou igual ao segundo
  
  = - primeiro argumento é igual ao segundo
  != - primeiro argumento é diferente do segundo

O programa "test" pode também fazer testes "unários", ou seja, com só um argumento. Por exemplo,

  arq="/tmp/arquivo"
  tmp=$arq
  i=1
  while [ -e $tmp ]; do
          i=$(($i+1))
          tmp=$arq$i
  done
  touch $tmp

Esse scriptzinho (note que não o fiz na linha de comando, mas indentado, para usá-lo a partir de um arquivo; funciona dos dois jeitos) só sai do loop quando achar um nome de arquivo que não exista. Ou, de forma mais didática, "enquanto existir (-e) o arquivo cujo nome está na variável $tmp, ele continua executado o bloco de comandos".

Alguns dos operadores unários mais comuns são:

  -e - arquivo ou diretório existe
  -f - é um arquivo (em oposição a ser um diretório)
  -d - é um diretório
  -x - arquivo tem permissão de execução para o usuário atual
  -w - arquivo tem permissão de escrita pelo usuário atual
  -r - arquivo tem permissão de leitura pelo usuário atual

Para mais detalhes, "man test".

Continuando:

  do echo $i

Logo após um "while <teste>", é preciso iniciar o primeiro comando com "do". Os seguintes (se houver), não.

A próxima linha mostra um exemplo de algo que não tem nada a ver com a estrutura do "while" em si, mas é um truquezinho legal de bash:

  i=$(($i + 1))

A construção "$((expressão))" é um operador matemático em bash. Isso é expandido para o resultado da expressão. Por exemplo,

  [rbp@muppets ~]$ echo $((2 + 3))=
  5
  [rbp@muppets ~]$ echo $((2 - 3))  # Funciona com números negativos=
  -1
  [rbp@muppets ~]$ echo $((2 * 3))=
  6
  [rbp@muppets ~]$ echo $((10 / 2))=
  5
  [rbp@muppets ~]$ echo $((3 / 2))  # Não usa casas decimais=
  1
  [rbp@muppets ~]$ =

Mas, como diz um amigo meu, voltando...

  done

Isso termina "oficialmente" o loop "while". A propósito, como pode ter sido notado, termina o "for" também.

Como foi dito acima, o while espera "verdadeiro" ou "falso". Eu nunca disse que esperava isso só do programa "test" :)

Com efeito, qualquer expressão pode ser usada, e seu valor de retorno será utilizado para determinar se é "verdadeiro" ou "falso". Para quem não sabe, todo programa em Unix retorna um valor ao terminar sua execução. Normalmente, se tudo correu bem o valor retornado é 0 (zero). Se há algum erro, o valor retornado, diferente de zero, indica o tipo de erro (veja as manpages dos programas; "man fetchmail" seção "exit codes" é um bom exemplo). Portanto, ao contrário do que programadores de C ou Perl poderiam achar intuitivo (dentro de um "while", ou uma condição em geral), um programa que retorna 0 é considerado "verdadeiro" aos olhos do "while".

Assim, podemos fazer:

  while w | grep -qs rbp; do
          sleep 5s
  done
  echo 'rbp acaba de sair do sistema!'

Nesse exemplo, o while checa o retorno da expressão "w | grep -qs rbp". Isso retorna "verdadeiro" quando o grep acha "rbp" na saída do comando "w". Toda vez que achar, espera 5 segundos e checa de novo. Quando não achar, sai do loop e mostra um aviso de que a última sessão do rbp foi fechada.

Pra finalizar: se você quiser fazer um loop infinito, pode usar ":" (dois pontos) como condição sempre verdadeira:

  while : ; do 
          echo 'Emacs rules!'
  done

Isso vai imprimir uma constatação sábia infinitamente, até você usar C-c (Ctrl + C). Normalmente, isso é utilizado com alguma condição de parada. Mas "if" fica pra outra dica :)



Veja a relação completa dos artigos de Rodrigo Bernardo Pimentel

 

 

Opinião dos Leitores

Seja o primeiro a comentar este artigo
*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