2>&1を使用して、stdout / stderrをBASHスクリプト内のいくつかのコマンドのうちの1つのコマンドにのみ指定します。

2>&1を使用して、stdout / stderrをBASHスクリプト内のいくつかのコマンドのうちの1つのコマンドにのみ指定します。

初めて投稿するので、ご了承ください。

私は最初のBASHスクリプトを作成し、systemdを使用してタイマーからそれを呼び出します(最初のsystemdデバイスでもあります!)。スクリプトは毎日バックアップを実行し、通知転送を使用して自分のデスクトップに通知を送信します。

いくつかの追加のロギングをJournalctlに指示したいが、いくつかの特定の単一のコマンドに対してのみ可能です。私は2>&1を使用した:

df -h | grep --color=never /mnt/Backups 2>&1

ただし、これにより、通知を介して送信されたデスクトップ通知にバックアップが成功したかどうかに関係なく、「成功」と表示されます(systemdは正常に完了します)。 2>&1と通知の送信を削除すると、スクリプトのBorg作業部分に正しい通知提案が提供されているかどうかをテストしました(成功と失敗の両方をテスト)。

それでは、どのようにリダイレクトを開始および停止し、それをJournalctlに表示し、私の通知を正確に表示しますか?

これは私のスクリプトの一部です。

df -h | grep --color=never /mnt/Backups 2>&1

SUCCESS=$?
echo $SUCCESS

## Use DESTOP Notifications.
if [ "${SUCCESS}" = "0" ]; then
notify-send -a Borg 'Operation was successful!' '~/.local/bin/borg-backup.sh' -u normal -i checkbox-checked-symbolic
else
notify-send -a Borg 'Operation was *NOT* successful' '~/.local/bin/borg-backup.sh' -u critical -i dialog-error
exit 1
fi 

ありがとうございます:)

答え1

まず、grepの出力をstderrに送信したいとします。 2>&1はstderrをstdoutにリダイレクトします。 1>&2をgrepする必要があるかもしれません。

次に、リダイレクトは対応する単一のコマンドに対してのみ機能します。持続しないため、リダイレクトを開始および停止することは問題になりません。

第三に、私は「成功」を得ることができません(systemdはそれをうまく行います)。テストしたのは、df -hの出力に/mnt/Backupsが記載されているということだけです。他のいくつかの要因がプロセスを中断する可能性があります。

第四に、パイプラインのプロセス状態が予期しない場合があります。各プロセスの状態はPIPESTATUS配列に書き込まれます。パイプライン全体の状態は複雑です。特に、リダイレクトを含むパイプはサブシェルで実行できます(したがって、デフォルトのシェルはストリームをそのまま残します)。この場合、私はあなたの成功がパイプラインの最後のコマンドではなく、サブシェル自体の終了状態に関連していると信じる準備ができています。

私はそれを直接使うのに十分信頼できないので、このことについてあいまいです。私の考えは、次のように状態ではなくテキストをチェックすることです。

MOUNT="$( df -h | grep --color=never /mnt/Backups )"
echo 1>&2 "Mount test gets ${MOUNT:-Nothing}"

if [[ "${MOUNT}" = "/mnt/Backups" ]]; then ...

これらは診断するのが難しいです。私はRC=$?、コマンド状態の保存、echo $?コマンド状態の表示、declare -p PIPESTATUS状態配列の表示、およびRP="$( declare -p PIPESTATUS )"状態配列の保存の使用方法を学んでいます。

問題は、これら4つ(変数への割り当てを含む)はすべてコマンドであり、状態がゼロにリセットされることです。したがって、複数のチャネルを介して初期コマンド状態を見ることはできません。状態は一時的ですが、データは永遠です。

最良のメカニズムは、grepの数を一致させ、grep -c返された数を変数に格納することです。 grep が標準入力を読み込んだ場合、名前を出力しないので、ファイル名を捨てる必要はありません。

大容量ファイルの改善でgrep -l最初の一致が見つかったら終了するには、.を使用します(grep -c最後まで計算を続ける必要があります)。grep -lテストが""実行されるか、またはに対して実行されるように一致を含むファイル名を出力します"(standard input)"

関連情報