あるプロセスから別のプロセスに出力をパイプし、最初のプロセスに出力がある場合にのみ実行する方法は?


23

からの出力がある場合、このコマンドを電子メールのみに書き換えるにはどうすればよいmailq | grepですか?

mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email

これは1行でも可能ですか?

パイプが空かどうか確認し、電子メールの送信よりも一般的なケースでない場合は、データに対してコマンドを実行するをご覧ください


回答:


19

この操作には一時ファイルを使用する必要があると思うので&&、grepが次のような一致を示す終了ステータスを返した場合にのみ、オペレーターを使用してメールコマンドを実行できます。

TMPFILE=`mktemp /tmp/mailqgrep.XXXXXX`; mailq | egrep 'rejected|refused' -A5 -B5 > "$TMPFILE" && mail -s 'dd' email@email < "$TMPFILE"; rm "$TMPFILE"

一時ファイルがどこかに貼り付いていることを気にせず、静的な名前を使用できる場合は、特別な命名と削除をスキップできます。

 mailq | egrep 'rejected|refused' -A5 -B5 > /tmp/mailqgrep && mail -s 'dd' email@email < /tmp/mailqgrep

編集:glennの答えを見た後、私はこれでもう少し遊んで、明らかに$()構文を使用して変数を割り当てるとコマンドの終了コードが返されるので、文字列の長さに使用したテストをスキップして代わりに使用できます。ここでは、すべて1つのコマンドに含まれています。

data=$(mailq | egrep 'rejected|refused' -A 5 -B 5) && mail -s 'dd' email@email <<< "$data"

編集2:サイモンの答えを見た後、mailプログラムをチェックアウトしました。デフォルトで彼が説明する方法では動作しませんが、そのためのオプションがあります。manページから:

-E送信メッセージの最初または唯一のメッセージ部分にテキストが含まれていない場合、メッセージを送信せずにサイレントに破棄し、プログラムの起動時にskipemptybody変数を効果的に設定します。これは、cron(8)によって開始されたスクリプトからメッセージを送信するのに便利です。

これを可能にする:

mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -E -s 'dd' email@email

1
コラボレーションの力!!
グレンジャックマン

3
最適なソリューションを最上部に移動することで、この答えを改善できると思います。
マークブース

@Wildcard入力パラメーターmktempが引用を必要とするものを返さないのであれば、その編集は不要です。
カレブ

2
知っている。あなたは引用符時々必要であると理解するのを気にする数少ない人の一人です(そしてそれらを意図的に省略します)。ただし、を明示的に呼び出す場合を除き、デフォルト引用符で囲む必要がありますglob(split(var))。ここで単語分割やファイルグロブ拡張は必要ないので、それらを要求しないでください。また、このサイトで正しい方法を示す必要があります
ワイルドカード

@Wildcardフェア。私は一般的に実行するzshと、実際にいない私は彼らのためにお願いしない限り、このようなケースではグロブや単語分割を取得しますが、ここでの回答のためにではなく、原則のうち引用ターゲット環境を知ることは結構です。
カレブ

11

ユーティリティプログラムifneは、この目的のために明示的に存在します。標準入力が空でない場合にコマンドを実行します。

mailq | egrep 'rejected|refused' -A 5 -B 5 | ifne mail -s 'dd' email@email

ifneコマンドは、moreutilsパッケージの一部であり、「Unixが幼かった頃、誰も書くことを考えていなかったUnixツールのコレクションが増えている」と言われています。


8

出力を変数に保存し、文字列の長さがゼロ以外の場合にメールコマンドを呼び出すことができます。

data=$(mailq | egrep 'rejected|refused' -A 5 -B 5)
[[ -n "$data" ]] && mail -s 'dd' email@email <<< "$data"

1行の場合、2つのコマンドをセミコロンで結合します。


1
一時ファイルの代わりに変数を使用するための小道具。これにより、変数の割り当てを行ったコマンドの終了コードがどこにあるのかを考えるようになりました。更新された回答を参照してください。
カレブ

7

オプションmailとともに使用し-Eます。私のMacでは、MAIL(1)は-Eフラグが空の本文を含む電子メールを送信しないと言います。

-E本文が空のメッセージを送信しません。これは、cron(8)スクリプトからエラーをパイプするのに役立ちます。

私のMacでは、次のテストを実行しました。ファイルfile_does_existは存在しますが、ファイルは存在しないことに注意してくださいfile_does__not_exist

これは私に電子メールを送信します:

$ ls file_does_exist | egrep 'file' -A5 -B5 | mailx -E -s 'test' stefan@example.org

これはしません。コマンドls file_does_not_exist | egrep ...は出力を生成しないことに注意してください。

$ ls file_does_not_exist | egrep 'file' -A5 -B5 | mailx -E -s 'test' stefan@example.org
ls: file_does_not_exist: No such file or directory

カレブはあなたを打ち負かしました。
ジル 'SO-悪であるのをやめる'

1
彼は4.75時間だけ私を打ちました:)。私は彼の長い答えでこの詳細を見逃した。
ステファンLasiewski

5

この特定のケースでは、あなたの場合はmailサポート-Eオプション、それを使用しています。一般的な場合、1文字を読み取ろうとすることができます。ある場合は、後処理コマンドを開始し、ファイルの残りからその文字をフィードします。

pipe_if_not_empty () {
  a=$(dd bs=1 count=1 2>/dev/null; echo .)  # read at most one character
  if [ "$a" != "." ]; then                  # if there were two characters,
    { printf %s "${a%.}";                   # then output the first character
      cat; } |                              # and the rest of the input   
    "$@"                                    # into the specified program
  fi
}

mailq | egrep 'rejected|refused' -A 5 -B 5 |
pipe_if_not_empty mail -s 'dd' email@email

の便利な使用法に注意してくださいcat。を追加echo .すると、入力の最初の文字が改行であってもこの関数が機能します($(…)構造体が端末の改行を削除することに注意してください)。

ほとんどのシェル(zsh以外、私が知る限り)では、ファイルがヌル文字で始まる場合、このコードは空であると見なします。それを修正することは、読者の課題として残されています。(ヒント:od最初のサブシェルで使用し、最初のprintfバイトを出力します。)(解決策:パイプが空かどうかを確認する方法)ファイルが現在の有効な文字ではないバイトで始まる場合、同じ問題が発生する可能性がありますロケール; このコードをで実行すると、簡単に修正できますLC_ALL=C


ばかげているが、おそらく別のシナリオで役立つ場合は+1 :)好奇心から、なぜ空の文字列をテストするのではなく、ドットを注入してテストするのですか?入力がドットで始まる場合、問題は発生しませんか?readこれを使用してこれを簡素化できますか?
カレブ

@カレブ:はい、私はタイトルの質問に答えていて、特定の状況には答えていないと述べたはずです。ドットの説明については、私の編集を参照してください。readポータブルshでは、空の最初の行と空のファイルを区別できないと思います(bash、kshまたはzshでは可能かもしれません)。
ジル「SO-悪であるのをやめる」


1

最近ifnemoreutilsパッケージの一部であるコマンド名について学びました。この特定の問題を解決するために使用できる場所。

ifne-標準入力が空でない場合にコマンドを実行します

manページの例、

EXAMPLE
       find . -name core | ifne mail -s "Core files found" root

0

パーツtest -s /dev/stdinからの出力があるかどうかを確認するために使用してコマンドを書き換えることができますmailq | grep

- mailq | egrep 'rejected|refused' -A 5 -B 5 | mail -s 'dd' email@email
+ mailq | egrep 'rejected|refused' -A 5 -B 5 | (test -s /dev/stdin && cat) | mail -s 'dd' email@email
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.