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이 실행되기 전에 로그를 자르는 것부터 시작했습니다 .
고쳐 쓰다
이전 답변에서는 마음에 들지 않았습니다. 동일한 파일에 두 개의 프로세스가 추가되어 먼저 잘라야 했습니다. 다른 해결책을 찾았습니다.
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 $?
그리고 실패한 문이 0이 아닌 값을 반환하는지 확인하세요.
따라서 스크립트에서 오류 처리를 수행하고 오류가 발생하면 메일을 통해 로그를 보내는 것이 좋습니다. 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:~$