test='yes'
tentará ler a saída completa de yes e atribuirá isso à variável test .
Como a saída de yes é infinita, essa atribuição invocará um loop infinito.
Sob o capô, ele usa o mecanismo do sistema operacional pipe , assim como a operação | .
test='yes'
é como
yes | thisShell.slurpInputAndSaveToVariable test
cat não tenta sugar toda a sua entrada, o que torna possível que yes e cat sejam executados simultaneamente como um produtor de streaming (e infinito neste caso) e um par de consumidores.