IFS - Inter Field Separator
Por Julio Neves
Data de Publicação: 03 de Janeiro de 2007
Lendo o artigo intitulado Atribuição de Valores a Variáveis em Shell Scripts me senti tentado a escrever esta dica.
O shell tem uma variável interna chamada IFS - Inter Field Separator (será Tabajara? :) - cujo valor default podemos obter da seguinte forma:
$ echo "$IFS" | od -h 0000000 0920 0a0a 0000004
O programa od com a opção -h foi usado para gerar um dump hexadecimal da variável. E lá podemos ver:
| Valor Hexadecimal | Significado |
|---|---|
| 09 | <TAB> |
| 20 | Espaço |
| 0a | <ENTER> |
Ou seja os separadores entre campos (tradução livre de IFS) default são o <TAB>, o espaço em branco e o <ENTER>. O IFS é usado em diversas instruções, mas seu uso é muito comum em par com o for e/ou com o read. Vejamos um exemplo semelhante ao dado no Cantinho do Shell de 15/12/2006, que me inspirou a escrever este artigo.
$ cat script1.sh
#!/bin/sh
while read linha
do
awk -F: '{print $1}' /etc/passwd > /dev/null
done < /etc/passwd
Como podemos ver este script não faz nada (sua única saída foi enviada para /dev/null para não deturpar os tempos de execução), mas vamos usá-lo para avaliação dos tempos de execução.
Este script foi alterado, trocando o awk pelo cut, e ficando com a seguinte cara:
$ cat script2.sh
#!/bin/sh
while read linha
do
echo $linha | cut -f1 -d: > /dev/null
done < /etc/passwd
Mais uma outra alteração, usando 99% de intrínsecos do Shell (exceto o comando echo) desta vez tomando partido do IFS:
$ cat script3.sh
#!/bin/sh
IFS=:
while read user lixo
do
echo $lixo > /dev/null
done < /etc/passwd
Neste último exemplo, transformamos o separador padrão em dois-pontos (:) e usamos sua propriedade em conjunto com o read, isto é, o primeiro campo veio para a variável user e o resto para a variável lixo.
Em seguida, fiz um script usando Shell quase puro (novamente o echo foi o vilão). Repare a construção ${linha%%:*}, que é um intrínseco (built-in) do Shell que serve para excluir da variável linha o maior casamento com o padrão especificado (:* - que significa "de dois-pontos em diante"), ou seja, excluiu de linha tudo a partir do último dois-pontos, contado da direita para a esquerda.
Dica: quem não conhece o macete acima, não pode deixar de ler a seção referente a expansão de parâmetros em: http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo009
$ cat script4.sh
#!/bin/sh
while read linha
do
echo ${linha%%:*} > /dev/null
done < /etc/passwd
Para finalizar, adaptei o script escrito pelo incansável Rubens Queiroz que, exceto pelo awk, é Shell puro.
$ cat script5.sh
#!/bin/sh
for user in `awk -F: '{print $1}' /etc/passwd`
do
echo $user > /dev/null
done
Agora, o mais importante: reparem os tempos da execução de cada um deles:
$ time script1.sh real 0m0.123s user 0m0.032s sys 0m0.032s $ time script2.sh real 0m0.297s user 0m0.152s sys 0m0.084s $ time script3.sh real 0m0.012s user 0m0.004s sys 0m0.004s $ time ./script4.sh real 0m0.012s user 0m0.004s sys 0m0.008s $ time ./script5.sh real 0m0.014s user 0m0.012s sys 0m0.004s
Reparem que estas diferenças de tempo foram obtidas para um arquivo com somente 29 linhas. Veja:
$ wc -l /etc/passwd 29 /etc/passwd
Um outro uso interessante do IFS é o que vemos a seguir, primeiramente usando o IFS default que como vimos é <TAB>, Espaço e <ENTER>:
$ Frutas="Pera Uva Maçã" $ set - $Frutas $ echo $1 Pera $ echo $3 Maçã
Agora, vamos alterar o IFS para fazer o mesmo com uma variável qualquer, e para tal vamos continuar usando o famigerado /etc/passwd:
$ Root=$(head -1 /etc/passwd) $ echo $Root root:x:0:0:root:/root:/bin/bash $ oIFS="$IFS" $ IFS=: $ set - $Root $ echo $1 root $ echo $7 /bin/bash $ IFS="$oIFS"
Senhores, neste artigo pretendi mostrar duas coisas:
- O uso do IFS que, infelizmente para nós, é uma variável pouco conhecida do Shell e
- Que quanto mais intrínsecos do Shell usamos, mais veloz e performático fica o script.
Quaisquer dúvidas favor postar na página e me mandar um aviso de alerta para julio.neves@gmail.com.
Que 2007 seja o ano livre para todos nós.
Veja a relação completa dos artigos da coluna Cantinho do Shell
Para se manter atualizado sobre as novidades desta coluna, consulte sempre o newsfeed RSS
Para saber mais sobre RSS, leia o artigo O Padrão RSS - A luz no fim do túnel.



