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.


o comando intrínseco (built-in) mapfile

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!

Saiba mais!

Adicionar comentário

* Campos obrigatórios
5000
Powered by Commentics

Comentários

Nenhum comentário ainda. Seja o primeiro!


Veja a relação completa dos artigos de Julio Cezar Neves