De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.
Colaboração: Julio Cezar Neves
Data de Publicação: 14 de agosto de 2019
O bash 4.0, nos trouxe uma novidade: o comando intrínseco (built-in) mapfile, cuja finalidade é ler linhas da entrada primária (stdin) para dentro de um vetor indexado, sem fazer loop ou substituição de comando. Sua sintaxe é a seguinte:
mapfile [OPCS] [VETOR]
Onde os dados recebidos pela entrada primária irão para o vetor VETOR. Caso ele não seja especificado, a variável do sistema, MAPFILE, se incumbirá de receber esses dados.
As principais opções OPCS são:
| Opção | Efeito |
|---|---|
-n QTD |
Copia, no máximo, QTD linhas |
-O ORIGEM |
Usa ORIGEM como o menor índice de VETOR |
-s QTD |
Descarta as primeiras QTD linhas |
-c QTD |
A cada QTD linhas lidas executa o que for especificado pela opção -c |
-C COD |
Executa o código Shell especificado em COD. O índice de VETOR é adicionado ao final |
Existem algumas formas de você copiar um arquivo para um vetor:
$ Vetor=($(cat Arquivo)) # 1? parênteses para gerar vetor $ read -a Vetor <<< $(cat Arquivo) $ mapfile Vetor < Arquivo
Mas o que importa aqui é o tempo, então faça:
$ seq 1000000 > Arquivo
e em seguida faa os seguintes testes:
$ time Vetor=( $(cat Arquivo)) $ time read -a Vetor <<< $(cat Arquivo) $ time mapfile Vetor < Arquivo
Você verá que a solução com o mapfile é pelo menos 10 vezes mais rápida que as outras. Então vamos brincar com o mapfile. Crie esse arquivo:
$ cat frutas abacate maçã morango pera tangerina uva $ mapfile vet < frutas $ echo ${vet[@]} # Lista todos os elementos de vetor vet abacate maçã morango pera tangerina uva
Vejamos como funcionam as suas principais opções:
$ mapfile -n3 vet < frutas # Para ler somente três linhas
$ echo ${vet[@]} # Exibe os dados
abacate maçã morango
$ echo ${!vet[@]} # Exibe os índices
0 1 2
$ unset vet # "Mata" o vetor
$ mapfile vet < frutas # Começando de novo
$ echo ${vet[@]}
$ echo ${!vet[@]}
0 1 2 3 4 5
$ mapfile -O 6 vet < frutas # Menor índice será o que já tinha mais 1
$ echo ${vet[@]}
abacate maçã morango pera tangerina uva abacate maçã morango pera tangerina uva
$ echo ${!vet[@]}
0 1 2 3 4 5 6 7 8 9 10 11
$ unset vet
$ mapfile -s 3 vet < frutas # Despreza três linhas iniciais de frutas
$ echo ${vet[@]}
pera tangerina uva
$ echo ${!vet[@]}
0 1 2
$ mapfile -c1 -C "echo -n carreguei o índice" < frutas
carreguei o índice 0 abacate
carreguei o índice 1 maçã
carreguei o índice 2 morango
carreguei o índice 3 pera
carreguei o índice 4 tangerina
carreguei o índice 5 uva
O mesmo resultado seria obtido se fizesse:
$ mapfile -c1 -C "printf 'carreguei o índice %d %s'" < frutas
carreguei o índice 0 abacate
carreguei o índice 1 maçã
carreguei o índice 2 morango
carreguei o índice 3 pera
carreguei o índice 4 tangerina
carreguei o índice 5 uva
No entanto, poderíamos desprezar os índices, que são automaticamente lançados para a saída, se não especificarmos a máscara do printf para recebê-los (no caso %d e %s), fazendo uma barra de progresso rústica usando essa técnica. Vejamos:
$ mapfile -c1 -C "printf '#'" < frutas
######$
Nesses últimos exemplos, não especificamos o nome do vetor. Assim sendo, o Bash mandou todos os dados para MAPFILE. Veja:
$ echo ${MAPFILE[@]}
abacate maçã morango pera tangerina uva
Isto é, foi lançado um jogo-da-velha (#) para cada elemento carregado no vetor. Isso é muito legal, mas se a quantidade de elementos for muito grande, a qualidade da apresentação será prejudicada. Para resolver isso, basta incrementar o valor da opção -c. Observe também que o prompt ficou colado na saída, sem saltar linha. Para resolver isso, o melhor é colocar um echo puro no final da linha. Vamos ver como carregar um vetor com 800.000 elementos:
$ printf '%s\n' {0..800000} | mapfile -c25000 -C 'printf "#"'; echo
################################
Como estamos gerando um vetor com 800.000 elementos, escrevendo um # a cada 25.000 elementos conseguiremos entender o papel de barra de progresso.
As inscrições para o curso Programação Shell Linux com o Professor Julio Neves estão abertas!