Следующее ifnotempty
функционируйте передает его вход по каналу к команде, переданной как аргумент, за исключением того, что она ничего не делает, если вход пуст. Используйте его для передачи по каналу source --foo
в sink --bar
путем записи 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
}
Примечания дизайна:
dd
не читая больше, чем один байт этому говорят читать на его стандартном входе.head -c 1
была бы подходящая замена для dd bs=1 count=1 2>/dev/null
на Linux.head -n 1
не подошло бы потому что head
обычно буферизует его вход и может считать больше, чем одна строка, которую он производит — и так как он читает из канала, дополнительные байты просто потеряны.read -r head
и даже read -r -n 1 head
не подходят здесь потому что, если первый символ является новой строкой, head
был бы установлен на пустую строку, лишив возможности различать пустой вход и вводить запуск с пустой строки.head=$(head -c 1)
потому что, если бы первый символ является новой строкой, замена команды разделила бы заключительную новую строку, лишив возможности различать пустой вход и вводить запуск с пустой строки.cat
</dev/stdin
для микроскопического увеличения производительности.Если Вы не возражаете хранить целые промежуточные данные в памяти, вот очень немного более простая реализация pipe_if_not_empty
.
pipe_if_not_empty () {
input=$(cat; echo a);
if [ "x$input" != x"a" ]; then
{ printf %s "${input%a}"; } | "$@"
fi
}
Вот немного более простая реализация со следующими протестами:
Снова, целые данные хранятся в памяти.
pipe_if_not_empty () {
input=$(cat);
if [ "x$input" != x"" ]; then
{ printf '%s\n' "${input}"; } | "$@"
fi
}
По крайней мере что-то вроде этого работает:
yourcommand | if [ $(wc -c) -gt "0" ]; then yourothercommand; fi
Обратите внимание на то, что вышеупомянутое рассмотрит переводы строки и другие специальные символы, как произведено, таким образом, пустая строка передала этому, если оператор рассмотрят как вывод. Просто повысьте предел-gt, если Ваш вывод должен обычно быть выше, чем 1 байт :)
Вместо sender | receiver
:
tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | receiver; fi; }
sender | tester
Или Вы могли сделать это более общей целью путем изменения его для принятия программы получения как аргумент как в ответе Gilles:
tester () { local a=$(</dev/stdin); if [[ $a ]]; then printf '%s\n' "$a" | "$@"; fi; }
sender | tester receiver
ifne (1) от moreutils делает точно это. Moreutils доступен как пакет, по крайней мере, в Debian и Ubuntu, вероятно, в других дистрибутивах также.