É um pouco difícil, mas factível:
function die {
print -ru2 -- "E: $*"
exit 1
}
function psubin {
local stdin=$(cat; echo .) pipe
pipe=$(mktemp /tmp/psub.XXXXXXXXXX) || die mktemp
# this is racy
rm -f "$pipe"
mkfifo "$pipe" || die mkfifo
(
# don’t block parent
exec <&- >&- 2>&-
# write content to FIFO
print -nr -- "${stdin%.}" >"$pipe"
# signal EOF to reader, ensure it’s not merged
sleep 0.1
:>"$pipe"
# clean up
(sleep 1; rm -f "$pipe") &
) &
print -nr -- "$pipe"
}
diff -u $(echo abc | psubin) $(echo def | psubin)
Os problemas que você e eu encontramos aqui são:
-
mkfifo
reclama, a menos que você produza primeirorm
mktemp
- blocos mksh para o processo em segundo plano se ainda compartilhar quaisquer descritores de arquivo (stdin, stdout, stderr) com o pai (Nota: Esse provavelmente é o único caso de uso válido para usar
>&-
em vez de>/dev/null
e porque podemos garantir que esses fds não sejam mais usados, nem substituídos por novos fds) - como não temos stdin no processo em segundo plano, precisaremos armazenar em cache seu conteúdo, exatamente
- EOF com FIFOs (pipes nomeados) não é trivial. Vamos apenas deixar isso em diante ... (poderíamos fazer alguns truques ao tentar abrir o non-blocking FIFO para verificar se há um leitor e sinalizar EOF até o leitor morrer, mas isso funciona bem por enquanto )
- é melhor se o FIFO for removido após o uso…
Por outro lado: bom que estamos fazendo isso agora, porque eu eventualmente pretendo implementar o <(…)
no mksh, e então eu preciso saber o que observar, já que não podemos usar /dev/fd/
como faz o GNU bash, porque não é portátil o suficiente.