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이 실행되기 전에 로그를 자르는 것부터 시작했습니다 .

고쳐 쓰다

이전 답변에서는 마음에 들지 않았습니다. 동일한 파일에 두 개의 프로세스가 추가되어 먼저 잘라야 했습니다. 다른 해결책을 찾았습니다.

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 에서만 작동 하므로 sh.SHELL=/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 $?

그리고 실패한 문이 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:~$ 

관련 정보