crontabで標準出力のみをリダイレクトする方法は?

crontabで標準出力のみをリダイレクトする方法は?

stdoutログファイルにリダイレクトcrontabし、crontabからメールでエラーを通知したいと思います。

std および err ストリームをリダイレクトするには、次を選択します2>&1

[email protected]
0 23 * * * /home/john/import.sh > /home/john/logs/backup.log 2>&1

しかし、これはcrontabがエラーをキャッチして電子メール通知を送信するのを防ぐことはできませんか?そのため、標準出力のみをリダイレクトする方法を探しています。

私の問題は、私のimport.shスクリプトがmysqlインポートを実行していることです。奇妙なことは、エラーがなくてもcrontabが私に電子メールを送信することです。

mysql: [Warning] Using a password on the command line interface can be insecure.
Importing from file '/tmp/my.csv' to table `mytable` in MySQL Server at /var%2Frun%2Fmysqld%2Fmysqld.sock using 3 threads
[Worker001] Records: 340086  Deleted: 0  Skipped: 0  Warnings: 0
[Worker002] Records: 351334
...
File '/tmp/my.csv' was imported in 1 min 9.9572 sec at 59.91 MB/s

だから私はこれらのステートメントを記録し続け、エラーが発生した場合にのみ通知を送信する方法を探しています。


アップデート:次のようにcrontabをミラーリングします。

*/1 * * * * /opt/test.sh

テスト.sh:

#!/usr/bin/env bash

echo "just testing"
exit 0 

結果:crontabはいつも成功コードを含む標準出力であっても電子メール通知を送信します。しかし、なぜ?これが起こらないようにするにはどうすればよいですか?

答え1

次のことを試すことができます。

0 23 * * * :> /home/john/logs/backup.log && /home/john/import.sh 2> >(tee -a /home/john/logs/backup.log) >> /home/john/logs/backup.log

stderrstderrANDファイル(コマンドを介してtee)に同時にアクセスされ、stdoutファイルにのみアクセスされます。

リダイレクトが互いに上書きされないようにするには、ファイルに-aコマンドtee>>標準出力を追加する必要があります。tee

:> /home/john/logs/backup.log上記の理由でファイルに追加したので、各cronが実行される前にログを切り捨てることから始めました。

修正する

以前の答えでは気に入らなかった。同じファイルに2つのプロセスが追加され、最初にカットする必要がありました。別の解決策が見つかりました。

0 23 * * * (( /home/john/import.sh 2> >(tee /proc/self/fd/3) 1>&3 3>&- ) 3>&1 1>&2) |cat > /home/john/logs/backup.log

bashPOSIXではなくPOSIXでのみ機能するためshSHELL=/bin/bash

これは私がここでやっていることを説明する試みです。

  1. ((...) 3>&1 1>&2)

これにより、新しいファイル記述子が生成されます。サムこれはパイプfd 1の内容にリダイレクトされますcat。 fd 1 は fd 2 が保持するすべての項目に移動します。これは端末(またはあなたの場合はcronの入力)です。

  1. /home/john/import.sh 2> >(tee ... ) 1>&3 3>&-

スクリプトは stdout を fd 3 が保持するもの (つまりcat. を指すパイプ) として指定し、 stderr は tee で指定します。

もう必要ないのでfd 3を閉じます。スクリプトの標準出力は、3が保持するすべての項目に移動しました。

  1. tee /proc/self/fd/3

teeはfd 3の内容に両方書きます(もう一度パイプされていますcat)。そして端末に(またはあなたの場合はcronへの入力として)

  1. (...) |cat > /home/john/logs/backup.log

catストリームは標準入力から読み取られ、ファイルに書き込まれますbackup.log

結果:
  • スクリプトは標準出力を標準入力に書き込みますcat
  • スクリプトはstderrも作成しますtee
    • tee入力(スクリプトのstderr)を次に記録します。
      • 端末
      • 標準入力cat
  • cat以下から入力を受けてください。
    • スクリプトの標準出力
    • スクリプトの標準エラー(pass tee
  • catstdin から取得した内容がファイルに書き込まれます。
  • 実際にcronに返される唯一のものはスクリプトのstderrです(やはりを通してtee)。

答え2

予約されたこと

[email protected]
0 23 * * * /home/john/import.sh

import.sh

#!/bin/bash

exec 3>&1 # Save a reference to current STDOUT as file descriptor 3
# Redirect stdout and stderr to the log file
exec >>"/home/john/logs/backup.log" 2>&1

echo "$(date +%Y%m%dT%H%M) info: job started"

output_from_mysql_import_operation=$(
  mysql <data-to-import.sql 2>&1
)
mysql_exit_status=$?
if [[ $mysql_exit_status != 0 ]]; then
  # This is sent to file descriptor 3, which is the original stdout
  # Thus, cron will collect this and send an email
  cat <<EOF >&3
cron job failed for script $0 at $(date +%Y%m%dT%H%M)

An error occurred during the import operation.

The mysql exit status code was $mysql_exit_status.

The output from mysql follows.

$output_from_mysql_import_operation
EOF

  # This will end up in the log file
  cat <<EOF
$(date +%Y%m%dT%H%M): error: mysql exited with a non-zero exit status"

The mysql exit status code was $mysql_exit_status.

The output from mysql follows.

$output_from_mysql_import_operation

Exiting script
EOF
  exit 1
fi

echo "$output_from_mysql_import_operation"
echo
echo "$(date +%Y%m%dT%H%M) info: job completed successfully"

答え3

import.shファイルは実際に何をしますか?このようなコマンドを実行すると仮定すると、mysql次のものを返す必要があります。終了コード実行結果によると。その後、終了コードを確認してください。

努力する:

echo $?

そして、失敗したステートメントがゼロ以外の値を返すことを確認してください。

したがって、スクリプトでエラー処理を実行し、エラーが発生した場合は、メールでログを送信することをお勧めします。 stdoutとstderrをファイルに記録しますが、stderrをフィルタリングするためにcronを使用しないでください。

答え4

*/1 * * * * /opt/test.sh 1>tmp.log

テストサンプル:

@Station:~$ ls /var 1>/dev/null
@Station:~$ ls /varr 1>/dev/null
ls: cannot access '/varr': No such file or directory
@Station:~$ # splitting args:
@Station:~$ ls 1>/dev/null -- /var
@Station:~$ ls 1>/dev/null -- /varr 
ls: cannot access '/varr': No such file or directory
@Station:~$ 

関連情報