Esta é uma pergunta muito interessante e eu tive que experimentar por um tempo, mas a resposta é realmente super simples!
Como funciona a saída de progresso do git ? Ele mostra uma única linha de status com uma porcentagem de progresso e atualiza o tempo todo até que seja concluído. Ele faz isso não imprimindo um avanço de linha \n , mas um caractere retorno de carro \r no final da linha de progresso, o que faz com que o cursor de saída retorne novamente ao início da linha pronto para sobrescrever a última linha escrita novamente com um valor atualizado.
Você pode observar isso canalizando a saída de git através de cat -A , que não interpreta caracteres invisíveis, mas os exibe, por exemplo, \r torna-se ^M e as quebras de linha também são denotadas com $ :
Cloning into 'MyRepository'...$
remote: Counting objects: 2317, done. $
Receiving objects: 0% (1/2317) ^MReceiving objects: 1% (24/2317) ^MReceiving objects: 2% (47/2317) ^MReceiving objects: 3% (70/2317) ^MReceiving objects: 4% (93/2317) ^MReceiving objects: 5% (116/2317)
[...]
Agora, por que isso afeta read ? É óbvio, como diz help read (extrair, ênfase minha):
Read a line from the standard input and split it into fields.
read espera por quebras de linha ( \n ) antes de terminar. A saída de git não continha nenhuma quebra de linha durante a exibição de progresso, portanto read não foi concluído. Somente depois que a exibição de progresso foi concluída e git realmente imprimiu a próxima linha, read consumiu toda a saída, incluindo todos os estados intermediários e retornos de carro, e você o repetiu dentro do seu loop. Se você canalizar a echo ou done a cat -A , verá a mesma saída cheia de ^M s, como acima.
O que você pode fazer para permitir que read capture todas as linhas de progresso intermediárias é traduzir todos os retornos de carro para quebras de linha reais, canalizando o material através de tr \r \n . Dessa forma, cada estado é impresso em uma nova linha, em vez de sobrescrever a linha anterior.
Então, o loop completo que você usou poderia ter a seguinte aparência:
git clone --progress http://someRepo 2>&1 | tr \r \n |
while read -r line ; do
echo "bypassed: ${line}"
done
No meu sistema, a saída mostrada no terminal por essa solução ainda não é totalmente fluente e gagueja um pouco, mas não consegui melhorar ainda mais. Pelo menos agora você tem o resultado real "progresso".