Сделайте условное выражение канала по непустому возврату

Существует ли способ передать вывод по каналу одной функции другому, но только если существует вывод?

16
задан 12.11.2010, 11:49

4 ответа

Следующее 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
}

Примечания дизайна:

  • Я ожидал бы, что эта реализация будет работать над всеми платформами POSIX/Unix, хотя строго говоря это не совместимо стандартами: это полагается 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) потому что, если бы первый символ является новой строкой, замена команды разделила бы заключительную новую строку, лишив возможности различать пустой вход и вводить запуск с пустой строки.
  • В ударе, ksh или zsh, можно заменить 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
}
9
ответ дан 07.12.2019, 10:46

По крайней мере что-то вроде этого работает:

yourcommand | if [ $(wc -c) -gt "0" ]; then yourothercommand; fi

Обратите внимание на то, что вышеупомянутое рассмотрит переводы строки и другие специальные символы, как произведено, таким образом, пустая строка передала этому, если оператор рассмотрят как вывод. Просто повысьте предел-gt, если Ваш вывод должен обычно быть выше, чем 1 байт :)

2
ответ дан 07.12.2019, 10:46

Вместо 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
2
ответ дан 07.12.2019, 10:46

ifne (1) от moreutils делает точно это. Moreutils доступен как пакет, по крайней мере, в Debian и Ubuntu, вероятно, в других дистрибутивах также.

9
ответ дан 07.12.2019, 10:46

Теги

Похожие вопросы