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
stderr
stderr
ANDファイル(コマンドを介して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
bash
POSIXではなくPOSIXでのみ機能するためsh
。SHELL=/bin/bash
これは私がここでやっていることを説明する試みです。
((...) 3>&1 1>&2)
これにより、新しいファイル記述子が生成されます。サムこれはパイプfd 1の内容にリダイレクトされますcat
。 fd 1 は fd 2 が保持するすべての項目に移動します。これは端末(またはあなたの場合はcronの入力)です。
/home/john/import.sh 2> >(tee ... ) 1>&3 3>&-
スクリプトは stdout を fd 3 が保持するもの (つまりcat
. を指すパイプ) として指定し、 stderr は tee で指定します。
もう必要ないのでfd 3を閉じます。スクリプトの標準出力は、3が保持するすべての項目に移動しました。
tee /proc/self/fd/3
teeはfd 3の内容に両方書きます(もう一度パイプされていますcat
)。そして端末に(またはあなたの場合はcronへの入力として)
(...) |cat > /home/john/logs/backup.log
cat
ストリームは標準入力から読み取られ、ファイルに書き込まれますbackup.log
。
結果:
- スクリプトは標準出力を標準入力に書き込みます
cat
。 - スクリプトはstderrも作成します
tee
。tee
入力(スクリプトのstderr)を次に記録します。- 端末
- 標準入力
cat
。
cat
以下から入力を受けてください。- スクリプトの標準出力
- スクリプトの標準エラー(pass
tee
)
cat
stdin から取得した内容がファイルに書き込まれます。- 実際に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:~$