데비안 8.1에서 나는 사용하고 있습니다불다stackoverflow.com 웹사이트에 액세스할 수 있는지 감지하는 기능:
(에코>/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "스택오버플로우에 액세스할 수 없습니다."
sh
이는 Bash에만 적용되며 .default 쉘에는 영향을 미치지 않습니다 cron
.
의도적으로 스크립트를 시도하면 다음과 같은 결과를 sh
얻습니다.
$ /bin/sh: 1: cannot create /dev/tcp/stackoverflow.com/80: Directory nonexistent
SHELL
따라서 다음을 개인 crontab( via 로 설정하지 않음 /bin/bash
) 에 넣으면 crontab -e
스크립트가 1분마다 실행되기를 원하므로 위의 오류가 이메일당 1분에 한 번씩 전송되기를 원합니다.
* * * * * (echo >/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "Stackoverflow에 액세스할 수 없습니다."
실제로 예상한 대로 /var/log/syslog
이 항목이 매분 실행되는 것을 볼 수 있습니다.
#sudo grep 스택오버플로우 /var/log/syslog 8월 24일18:58:01로컬호스트 CRON[13719]: (mat) CMD ((echo >/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "stackoverflow에 액세스할 수 없습니다.") 8월 24일18:59:01로컬호스트 CRON[13723]: (mat) CMD ((echo >/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "stackoverflow에 액세스할 수 없습니다.") 8월 24일19:00:01로컬호스트 CRON[13727]: (mat) CMD ((echo >/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "stackoverflow에 액세스할 수 없습니다.") ...
이 명령은 지난 2시간 동안 120회 이상 실행되었으며 출력을 wc -l
.
하지만, 이러한 120개 이상의 셸 명령(반복: 셸 명령 쌍이 유효하지 않음 /bin/sh
)이 실행되었으므로 다음과 같은 결과만 얻습니다.삼이메일:
첫 번째는 19:10:01, 두 번째는 20:15:01, 세 번째는 20:57:01입니다.
세 메시지의 내용은 모두 예상한 대로 정확하게 읽었으며 (의도적으로) 호환되지 않는 셸에서 스크립트를 실행할 때 예상되는 오류 메시지도 정확하게 포함했습니다. 예를 들어, 제가 받은 두 번째 이메일은 다음과 같았습니다(나머지 두 이메일은 거의 동일했습니다).
~에서[이메일 보호됨] 2015년 8월 24일 월요일 20:15:01 에서:[이메일 보호됨](크레인 데몬) 도착하다:[이메일 보호됨] 주제: Cron (echo >/dev/tcp/stackoverflow.com/80)&>/dev/null || echo "Stackoverflow에 액세스할 수 없습니다." ... /bin/sh: 1: /dev/tcp/stackoverflow.com/80을 생성할 수 없습니다: 디렉토리가 존재하지 않습니다`
/var/log/mail.log
님이 보낸 이메일 3개는 다음과 같습니다.오직지난 몇 시간 동안 보내고 받은 메시지입니다.
그렇다면 잘못된 스크립트에 의해 생성된 위 출력으로 인해 cron에서 수신할 것으로 예상되는 100개 이상의 추가 이메일은 어디에 있습니까?
결론적으로:
- 이 시스템에서는 메일이 올바르게 구성되어 있으며 문제 없이 메일을 보내고 받을 수 있습니다
/usr/bin/sendmail
. - Cron은 올바르게 설정되어 예상대로 작업을 인식하고 구성된 시간에 정확하게 실행합니다. 나는 다른 많은 작업과 예약 옵션을 시도했고 cron은 예상대로 정확하게 실행했습니다.
- 스크립트언제나출력을 작성하므로(아래 참조) cron이 호출할 때마다 출력을 이메일로 보낼 것으로 예상합니다.
- 결과는 가끔 나에게 우편으로 전달되며 대부분의 경우 무시됩니다.
위의 관찰 결과로 이어지는 명백한 오류를 해결하는 방법에는 여러 가지가 있습니다.
SHELL=/bin/bash
내 에서 그렇게 할 수 있습니다crontab
.heartbeat.sh
with를 만들고#!/bin/bash
호출 할 수 있습니다 ./bin/bash -c ...
inside 를 사용하여 스크립트를 호출할 수 있습니다crontab
.- 잠깐만요. 이 모든 것이
sh
.
그러나 이 중 어느 것도 이 문제의 핵심 문제를 해결하지 못합니다. 즉, 이 경우 cron
스크립트조차도 안정적으로 메일을 보낼 수 없다는 것입니다.언제나출력을 생성합니다.
나는 스크립트가 항상 wrong.sh
다음을 생성하여 출력을 생성한다는 것을 확인했습니다.고의로부적절한 쉘을 사용하면 표시되는 것과 동일한 오류가 /bin/sh
발생합니다 .)cron
#!/bin/sh (echo >/dev/tcp/stackoverflow.com/80) &>/dev/null || echo "Stackoverflow에 액세스할 수 없습니다."
이제 스크립트 호출을 반복하여 완료되는 항목이 있는지 확인할 수 있습니다.아니요출력을 생성합니다. 사용불다:
$ true인 경우; do [[ -n $(./wrong.sh 2>&1 ) ]] echo $?;
수천 번의 호출에도 불구하고 출력을 생성하지 않고 스크립트가 완료되는 상황을 재현할 수 없습니다.
이렇게 예측할 수 없는 행동이 나타나는 이유는 무엇일까요? 누구든지 이것을 재현할 수 있습니까? 나에게는 cron이 스크립트의 출력을 놓칠 수 있는 경쟁 조건이 있을 수 있는 것 같습니다. 아마도 대부분 오류가 셸 자체에서 발생하는 상황과 관련이 있을 것입니다. 감사합니다!
답변1
&
추가 테스트를 해보니 결과가 엉망이 될 것 같습니다 . 지적하신대로 &>/dev/null
그렇습니다세게 때리다문법, 아니쉿통사론. 결과적으로 sh
서브쉘이 생성되어 배경으로 설정됩니다. 물론 서브쉘은 echo
stderr을 생성하지만 내 이론은 다음과 같습니다.
- cron은 서브쉘의 stderr을 캡처하지 않으며
- 서브셸의 배경은 항상 성공적으로 완료되며
|| echo ...
.
...크론 작업에서 출력이 발생하지 않으므로 메일이 없습니다. vixie-cron 소스 코드를 읽어보니 작업의 stderr 및 stdout이 cron에 의해 캡처되지만 서브쉘에 의해 확실히 손실되는 것 같습니다.
/bin/sh 환경에서 직접 테스트해 보세요(여기에 "bar"라는 파일이 없다고 가정).
(grep foo bar) &
echo $?
답변2
다음 crontab을 사용하여 Ubuntu 15.04에서 동작을 재현할 수 있습니다.
* * * * * { echo job 0; } & sleep 5
* * * * * { echo job 1; } &
* * * * * { sleep 5; echo job 2; } &
job 0
매분마다 cron으로부터 다음 내용이 포함된 이메일을 받습니다.job 1
가끔(최근 10분 동안 5~6회), 없음 job 2
.
따라서 cron은 하위 프로세스가 종료될 때까지 기다린 다음 당시에 흡수할 수 있는 모든 stdout/stderr 출력이 포함된 이메일을 보내는 것처럼 보입니다. 고아가 된 손자 프로세스의 지연된 출력은 단순히 삭제됩니다.
답변3
위의 설명 외에도 조금 더 간단한 설명이 있을 수 있는지 궁금합니다.
모든 쉘은 작업을 수행하기 전에 명령줄을 확장/처리한다는 점을 기억하세요. 따라서 sh
"&"로 확장하면 명령줄이 종료되고 이를 백그라운드에 넣으려고 하며(기본적으로 낮은 우선순위) 리디렉션된 내용에 따라 stdin/stdout/stderr이 제대로 할당되지 않습니다. 따라서 "경합 조건"은 쉘(sh)이 라인을 처리하는 속도에 따라 달라질 수 있으며, 이는 분명히 시스템의 로드(및 이후에 시스템과 상호 작용하는 방식 cron
)에 따라 달라집니다.