Quero obter o número de bytes e o sha1sum da saída de um comando.
Em princípio, sempre se pode fazer algo como:
BYTES="$( somecommand | wc -c )"
DIGEST="$( somecommand | sha1sum | sed 's/ .*//' )"
... mas, para o caso de uso no qual estou interessado, somecommand
consome bastante tempo e produz uma grande quantidade de resultados, então prefiro chamá-lo apenas uma vez.
Uma maneira que vem à mente seria algo como
evil() {
{
somecommand | \
tee >( wc -c | sed 's/^/BYTES=/' ) | \
sha1sum | \
sed 's/ .*//; s/^/DIGEST=/'
} 2>&1
}
eval "$( evil )"
...o que parece funcionar, mas me faz morrer um pouco por dentro.
Gostaria de saber se existe uma maneira melhor (mais robusta, mais geral) de capturar a saída de diferentes segmentos de um pipeline em variáveis separadas.
EDIT: O problema no qual estou trabalhando no momento é em bash
, então estou mais interessado em soluções para esse shell, mas também faço muita zsh
programação, então também tenho algum interesse nessas soluções.
EDIT2: Tentei portar a solução de Stéphane Chazelas para bash
, mas não funcionou:
#!/bin/bash
cmd() {
printf -- '%1000s'
}
bytes_and_checksum() {
local IFS
cmd | tee >(sha1sum > $1) | wc -c | read bytes || return
read checksum rest_ignored < $1 || return
}
set -o pipefail
unset bytes checksum
bytes_and_checksum "$(mktemp)"
printf -- 'bytes=%s\n' $bytes
printf -- 'checksum=%s\n' $checksum
Quando executo o script acima, a saída que recebo é
bytes=
checksum=96d89030c1473585f16ec7a52050b410e44dd332
O valor de checksum
está correto. Não consigo entender por que o valor de bytes
não está definido.
EDIT3: OK, graças à dica do @muru, resolvi o problema:
#!/bin/bash
cmd() {
printf -- '%1000s'
}
bytes_and_checksum() {
local IFS
read bytes < <( cmd | tee >(sha1sum > $1) | wc -c ) || return
read checksum rest_ignored < $1 || return
}
set -o pipefail
unset bytes checksum
bytes_and_checksum "$(mktemp)"
printf -- 'bytes=%s\n' $bytes
printf -- 'checksum=%s\n' $checksum
Agora:
bytes=1000
checksum=96d89030c1473585f16ec7a52050b410e44dd332
INFELIZMENTE ...
... minha bytes_and_checksum
função para (impasse?) quando cmd
produz muito mais saída do que no meu exemplo de brinquedo acima.
De volta à prancheta...