A seguinte função ifnotempty
canaliza sua entrada para o comando passado como um argumento, exceto que não faz nada se a entrada estiver vazia. Use-o para canalizar source --foo
para sink --bar
escrevendo source --foo | pipe_if_not_empty sink --bar
.
pipe_if_not_empty () {
head=$(dd bs=1 count=1 2>/dev/null; echo a)
head=${head%a}
if [ "x$head" != x"" ]; then
{ printf %s "$head"; cat; } | "$@"
fi
}
Notas de design:
- Espero que esta implementação funcione em todas as plataformas POSIX / Unix, embora, estritamente falando, não seja compatível com os padrões: ela depende de
dd
não ler mais do que o byte que é contado para ler em sua entrada padrão. / li> - Acho que
head -c 1
seria um substituto adequado paradd bs=1 count=1 2>/dev/null
no Linux. - Por outro lado,
head -n 1
não seria adequado porquehead
normalmente armazena em buffer sua entrada e pode ler mais do que a linha que ela gera - e como está lendo de um canal, os bytes extras são perdidos. / li> -
read -r head
e mesmoread -r -n 1 head
não são adequados aqui porque se o primeiro caractere for uma nova linha,head
será definido como uma string vazia, impossibilitando a distinção entre entrada vazia e entrada começando com uma linha em branco. - Não podemos simplesmente escrever
head=$(head -c 1)
, porque se o primeiro caractere for uma nova linha, a substituição de comandos removerá a nova linha final, tornando impossível distinguir entre entrada vazia e entrada começando com uma linha em branco. - No bash, ksh ou zsh, você pode substituir
cat
por</dev/stdin
para um ganho de desempenho microscópico.
Se você não se importar em armazenar todos os dados intermediários na memória, aqui está uma implementação um pouco mais simples de pipe_if_not_empty
.
pipe_if_not_empty () {
input=$(cat; echo a);
if [ "x$input" != x"a" ]; then
{ printf %s "${input%a}"; } | "$@"
fi
}
Aqui está uma implementação um pouco mais simples com as seguintes ressalvas:
- Os dados produzidos pela fonte são considerados vazios se, e somente se, consistirem apenas em caracteres de nova linha. (Isso pode de fato ser desejável).
- Os dados alimentados no coletor terminam com exatamente um caractere de nova linha, independentemente de quantas novas linhas finais os dados produzidos pela origem terminam. (Isso pode ser um problema.)
Novamente, todos os dados são armazenados na memória.
pipe_if_not_empty () {
input=$(cat);
if [ "x$input" != x"" ]; then
{ printf '%s\n' "${input}"; } | "$@"
fi
}