Eu já "estagiei" na minha universidade e trabalhei com desenvolvimento para Linux, na verdade não foi estágio, e sim uma bolsa de iniciação científica, e lá eu acabei aprendendo dentre outras coisas a criar scripts bash. Desde então eu gosto de praticar e vi seu pedido como uma oportunidade. Acabei conhecendo as ferramentas
bc e
numfmt durante o desenvolvimento desse script, valeu a pena no final rs.
Para entender o funcionamento desse script você precisa executar os comandos por partes para ir entendendo como ele constrói a solução final, talvez a única coisa que você possa ter dificuldades em entender seja o uso de
expressões regulares, pois isso eu aprendi no meu curso de graduação, aqui tem informações sobre isso:
https://pt.wikipedia.org/wiki/Express%C3%A3o_regularVou tentar explicar o script por partes:
- Código: Selecionar todos
pacman -Qi *nomeDoPacote*
Exibi informações de um pacote.
- Código: Selecionar todos
pacman -Q
Exibi o nome de todos os pacotes instalados juntamente com a versão.
- Código: Selecionar todos
pacman -Q | cut -d' ' -f1
o comando cut da forma como está sendo invocado "recorta" apenas a primeira coluna da saída do comando pacman -Q, dessa forma eu obtenho apenas os nomes dos pacotes e descarto a versão.
- Código: Selecionar todos
pacman -Qi $(pacman -Q | cut -d' ' -f1)
Eu exibo informações de todos os pacotes instalados no sistema, incluindo o tamanho de cada pacote. A saída desse comando é enorme mas ela contém tudo o que preciso para o meu objetivo final que é calcular a soma do tamanho de todos esses pacotes.
- Código: Selecionar todos
grep -oiE [0-9]+,[0-9]+\ B
É aqui que entra a expressão regular, meu objetivo com o comando grep é recortar da saída do comando anterior apenas o tamanho dos pacotes, descartando todas as outras informações, através dessa expressão regular eu filtro a saída do comando anterior e consigo esse objetivo, para isso eu reparei que o tamanho dos pacotes sempre segue o padrão números,números B ou números,números KiB ou números,números MiB ou números,números GiB. Através da expressão eu filtro esse padrão.
- Código: Selecionar todos
cut -d' ' -f1
Com a saída do comando anterior eu tenho em mãos um stream de texto com o tamanho de todos os pacotes seguido da unidade de armazenamento (B, KiB, MiB, GiB), com o comando cut eu removo essa unidade e mantenho apenas o número.
- Código: Selecionar todos
paste -s -d+
Com esse comando eu começo a preparar a operação aritmética que vai ser realizada pelo último comando da cadeia de pipes (
bc), eu tenho um stream de texto com todos os números referentes ao tamanhos de todos os pacotes, para preparar esse stream para ser a entrada do comando
bc eu adiciono o sinal delimitador + entre cada um desses números, é isso que esse comando está fazendo.
- Código: Selecionar todos
sed 's/,/./g'
Aqui foi outra preparação para o comando bc, alguns dos números que eu tenho em mãos no stream de texto possuem parte fracionária e estão em um formato em que a parte decimal é separada da parte fracionária por uma virgula, ex: 121,20. O comando
bc não aceita essa notação com vírgula, então eu usei o comando sed para substituir todas as vírgulas por pontos.
- Código: Selecionar todos
B=$(pacman -Qi $(pacman -Q | cut -d' ' -f1) | grep -oiE [0-9]+,[0-9]+\ B | cut -d' ' -f1 | paste -s -d+ | sed 's/,/./g' | bc)
KiB=$(pacman -Qi $(pacman -Q | cut -d' ' -f1) | grep -oiE [0-9]+,[0-9]+\ KiB | cut -d' ' -f1 | paste -s -d+ | sed 's/,/./g' | bc)
MiB=$(pacman -Qi $(pacman -Q | cut -d' ' -f1) | grep -oiE [0-9]+,[0-9]+\ MiB | cut -d' ' -f1 | paste -s -d+ | sed 's/,/./g' | bc)
GiB=$(pacman -Qi $(pacman -Q | cut -d' ' -f1) | grep -oiE [0-9]+,[0-9]+\ GiB | cut -d' ' -f1 | paste -s -d+ | sed 's/,/./g' | bc)
Repare que eu executei o mesmo comando 4 vezes, para armazenar os tamanhos dos pacotes referentes a cada tipo de unidade de armazenamento (B, KiB, MiB, GiB), eu fiz isso porque preciso diferenciar entre as unidades durante a leitura do tamanho dos arquivos.
- Código: Selecionar todos
if [ -z "$B" ]; then let "B = 0"; fi
if [ -z "$KiB" ]; then let "KiB = 0"; fi
if [ -z "$MiB" ]; then let "MiB = 0"; fi
if [ -z "$GiB" ]; then let "GiB = 0"; fi
Aqui basicamente estou usando a estrutura de seleção "if" para verificar se algum dos valores anteriores não foi calculado (quando não existe nenhum pacote no sistema com uma determinada unidade, o que é frequente para a unidade GiB), e estou armazenando o valor zero na variável que ficou vazia para não ocorrerem erros no próximo comando.
- Código: Selecionar todos
$B+$KiB*1024+$MiB*1024*1024+$GiB*1024*1024*1024
Aqui estou convertendo todas as unidades para bytes, e somando todos os valores para no final obter o tamanho total de todos os pacotes em bytes.
- Código: Selecionar todos
sed 's/\./,/g'
Diferentemente do comando bc que faz a leitura de números fracionários usando . "ponto", o comando numfmt usa o formato com , "virgula", então estou substituindo o ponto pela vírgula novamente.
- Código: Selecionar todos
numfmt --to=iec-i --suffix=B
Aqui converto o número em bytes para a unidade de armazenando mais apropriada (calculada pelo comando numfmt automaticamente).
Tentei resumir como o script funciona por partes, no meu caso é mais fácil entender pois eu estudo isso (faço ciência da computação como curso de graduação), não sei se será simples para alguém que não tem familiaridade com programação. Mas como você parece que está querendo aprender deixo aqui essa ajuda rs.