você está aqui: Home → Colunistas → Cantinho do Shell
Data de Publicação: 22 de Janeiro de 2007
Primeiro um programador com complexo de inferioridade criou o redirecionamento de entrada e representou-o com um sinal de menor (<)
para representar seus sentimentos. Em seguida, outro sentindo-se pior ainda, criou o here document representando-o por dois sinais de menor (<<)
porque sua fossa era maior. O terceiro, pensou: "estes dois não sabem o que é estar por baixo"... Então criou o here strings representado por três sinais de menor (<<<).
Brincadeiras a parte, o here strings é utilíssimo e, não sei porque, é um perfeito desconhecido. Na pouquíssima literatura que sobre o tema, nota-se que o here strings é freqüentemente citado como uma variante do here document, com a qual discordo pois sua aplicabilidade é totalmente diferente daquela.
Sua sintaxe é simples:
$ comando <<< $cadeia
Onde cadeia é expandida e alimenta a entrada primária (stdin)
de comando.
Como sempre, vamos direto aos exemplos dos dois usos mais comuns para que vocês próprios tirem suas conclusões.
Substituindo a famigerada construção echo "cadeia" | comando
, que força um fork
, criando um subshell e onerando o tempo de execução. Vejamos alguns exemplos:
$ a="1 2 3" $ cut -f 2 -d ' ' <<< $a # normalmente faz-se: echo $a | cut -f 2 -d ' ' 2 $ echo $NomeArq Meus Documentos $ tr "A-Z " "a-z_" <<< $NomeArq Substituindo o echo ... | tr ... meus_documentos $ bc <<<"3 * 2" 6 $ bc <<<"scale = 4; 22 / 7" 3.1428
Para mostrar a melhoria no desempenho, vamos fazer um loop de 500 vezes usando o exemplo dados para o comando tr
:
$ time for ((i=1; i<= 500; i++)); { tr "A-Z " "a-z_" <<< $NomeArq >/dev/null; } real 0m3.508s user 0m2.400s sys 0m1.012s $ time for ((i=1; i<= 500; i++)); { echo $NomeArq | tr "A-Z " "a-z_" >/dev/null; } real 0m4.144s user 0m2.684s sys 0m1.392s
Veja agora esta seqüência de comandos com medidas de tempo:
$ time for ((i=1;i<=100;i++)); { who | cat > /dev/null; } real 0m1.435s user 0m1.000s sys 0m0.380s $ time for ((i=1;i<=100;i++)); { cat <(who) > /dev/null; } real 0m1.552s user 0m1.052s sys 0m0.448s $ time for ((i=1;i<=100;i++)); { cat <<< $(who) > /dev/null; } real 0m1.514s user 0m1.056s sys 0m0.412s
Observando este quadro você verá que no primeiro usamos a forma convencional, no segundo usamos um named pipe temporário para executar uma substituição de processos e no terceiro usamos here string. Notará também que ao contrário do exemplo anterior, aqui o uso de here string não foi o mais veloz. Mas repare bem que neste último caso o comando who está sendo executado em um subshell e isso onerou o processo como um todo.
Vejamos uma forma rápida de inserir uma linha como cabeçalho de um arquivo:
$ cat num 1 2 3 4 5 6 7 8 9 10 $ cat - num <<< "Impares Pares" Impares Pares 1 2 3 4 5 6 7 8 9 10
Outra forma legal de usar o here string é casando-o com um comando read, não perdendo de vista o que aprendemos sobre IFS
(veja mais sobre está variável no Papo de Botequim). O comando cat
com as opções -vet mostra o <ENTER> como $, o <TAB> como ^I e os outros caracteres de controle com a notação ^L onde L é uma letra qualquer. Vejamos então o conteúdo de uma variável e depois vamos ler cada um de seus campos:
Também podemos ler direto para um vetor (array) veja:
$ echo $Frutas Pera:Uva:Maçã $ IFS=: $ echo $Frutas Pera Uva Maçã # Sem as aspas o shell mostra o IFS como branco $ echo "$Frutas" Pera:Uva:Maçã # Ahhh, agora sim! $ read -a aFrutas <<< "$Frutas" # A opção -a do read, lê para um vetor $ for i in 0 1 2 > do > echo ${aFrutas[$i]} # Imprimindo cada elemento do vetor > done Pera Uva Maçã
Bem , por enquanto é só! Mas se vocês descobrirem algo de novo no uso de here strings, façam o favor de nos enviar para tornar o Cantinho um cantão cheio de dicas de bash :)
Se você quer um livro livre e online vá a www.julioneves.com