空でないリターンを条件とするパイプを作成する


16

ある関数の出力を別の関数にパイプする方法あります、出力ある場合のみですか?


回答:


9

次のifnotempty関数は、引数として渡されたコマンドに入力をパイプしますが、入力が空の場合は何も行いません。を書くことでパイプsource --fooに使用します。sink --barsource --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ません。標準入力で読み取るように指示された1バイト以上を読み取らないことに依存しています。
  • Linuxのhead -c 1適切な代替品になると思いますdd bs=1 count=1 2>/dev/null
  • 一方、通常は入力をバッファリングし、出力する複数の行を読み取る可能性があるhead -n 1ためhead、適切ではありません。パイプから読み取るため、余分なバイトが失われます。
  • read -r headread -r -n 1 head最初の文字が改行の場合headは空の文字列に設定され、空の入力と空行で始まる入力を区別することができないため、ここでも適切ではありません。
  • head=$(head -c 1)最初の文字が改行の場合、コマンド置換により最終改行が削除され、空の入力と空白行で始まる入力を区別できなくなるため、単に書くことはできません。
  • bashの、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
}

以下は、次の点で若干単純な実装です。

  • ソースによって生成されたデータは、改行文字のみで構成されている場合にのみ空と見なされます。(これは実際には望ましい場合があります。)
  • シンクに入力されたデータは、ソースによって生成されたデータがいくつの改行で終わっていても、ちょうど1つの改行文字で終わります。(これは問題になる可能性があります。)

繰り返しますが、データ全体がメモリに保存されます。

pipe_if_not_empty () {
  input=$(cat);
  if [ "x$input" != x"" ]; then
    { printf '%s\n' "${input}"; } | "$@"
  fi
}

17

これはあなたのために働くはずです

$ --a function-- | [ xargs -r ] --another function--

$ echo -e "\n\n" | xargs -r ls
$ # No output. ls did not run.
$ echo -e "\n\n1" | xargs -r ls
ls: cannot access 1: No such file or directory

それは簡単ですが、あなたのために働くはずです。「関数」が空の文字列または改行をパイプラインに送信する場合、xargs -rは「別の関数」への通過を防ぎます。

xargsのリファレンス:http ://www.oreillynet.com/linux/cmd/cmd.csp ? path = x/xargs

-r, --no-run-if-empty
Do not run command if standard input contains only blanks.


4

以下の関数は最初のバイトを読み込もうとし、成功した場合はそのバイトをエコーし​​、残りをcatsします。効率的で、100%ポータブルでなければなりません。

if_read() {
    IFS="" read -rN 1 BYTE && { echo -nE "$BYTE"; cat; } | "$@";
}

テストケース:

$ echo -n | if_read wc -c
$ echo | if_read wc -c
1
$ echo -en "\nX" | if_read wc -c
2
$

実行すると、この関数は失敗しますecho -en "\nX" | pipe_if_not_empty mail -s "Subject line here" foo@bar.com。これは、と思うlineと、hereいない対象にトークン、電子メールの両方の受信者です。私は"それを機能させるために対象の周囲から逃げなければなりません。ただし、pipe_if_not_empty受け入れられた回答からの機能は、何もエスケープしなくても機能します。
kuzzooroo 14

2

少なくともこのような何かが機能します:

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

上記では改行やその他の特殊文字が出力と見なされるため、そのifステートメントに渡された空の行は出力と見なされることに注意してください。通常、出力が1バイトよりも大きい場合は、-gt制限を上げます。


yourothercommandの出力は表示されませんyourcommand
追って通知があるまで一時停止します。

2

代わりに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
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.