시작 시 실행되고 주기적으로 실행되는 bash 스크립트를 만들겠습니다.
0 * * * * my_script
나는 사용자가 cron 작업을 실행하여 추가하고 my_script add 0 * * * *
, 작업을 실행하여 목록을 표시 my_script list
하고, my_script remove job_number
명령 출력에 작업 번호를 나열하여 작업을 제거할 수 있도록 사용자가 구성할 수 있기를 원합니다 my_script list
.
crontab 파일을 별도로 관리할 수 있다면 쉬울 것입니다. 하지만 crontab에는 사용자당 하나의 파일만 있는 것 같습니다(그렇지 않은 경우 알려주세요). 물론 crontab 파일을 직접 처리하는 것은 좋지 않은 해결책입니다.
그렇다면 cron 작업을 처리하는 올바른 방법은 무엇입니까? 또는 주기적으로 실행되는 스크립트를 처리하는 더 좋은 방법이 있습니까?
상황:
- 모든 사용자는 권한에 관계없이 이를 실행할 수 있어야 합니다.
- 종속성이 없습니다.
추가 질문:
주기적으로 실행되는 스크립트를 관리하는 적절한 방법을 찾을 수 없기 때문에 뭔가 잘못하고 있는 것 같습니다. 소프트웨어 설계 관점에서 소프트웨어의 예약된 작업을 관리하기 위한 인터페이스를 구현하는 것이 비현실적입니까? 일정 관리를 모두 사용자에게 맡겨야 하나요?
답변1
대부분의 Unix 시스템에서는 cron을 사용하는 것이 작업이 정기적으로 실행되도록 예약하는 올바른 방법입니다. 개인용 crontab을 사용하는 것은 사용자가 자신의 작업을 구성하는 가장 편리한 방법입니다. 시스템 작업은 루트(아래 스크립트를 사용하지 마세요!) 시스템 crontab에서는 일반적으로 형식이 약간 다릅니다(사용자 이름에 대한 추가 필드 포함).
여기에 간단한 스크립트가 있습니다. 모든 사용자는 이를 사용하여 자신의 개인 크론탭을 관리할 수 있습니다.
너무 적은 인수를 제공하지 않는 한 입력에 대해 어떤 종류의 유효성 검사도 수행하지 않습니다. 이 경우 불평이 발생합니다. 따라서 잘못된 crontab 항목을 추가하는 것이 전적으로 가능합니다.
이
remove
하위 명령은 줄 번호를 사용하여 crontab의 해당 줄에 있는 내용이 무엇이든 삭제합니다. 번호는 정리 없이 에 직접 전달됩니다sed
.crontab 항목을 추가할 때는 따옴표로 묶어야 합니다. 이는 견적 처리 방법에 영향을 미칩니다.~에crontab 항목 자체.
대부분의 문제는 상대적으로 해결하기 쉬워야 합니다.
#!/bin/sh
usage () {
cat <<USAGE_END
Usage:
$0 add "job-spec"
$0 list
$0 remove "job-spec-lineno"
USAGE_END
}
if [ -z "$1" ]; then
usage >&2
exit 1
fi
case "$1" in
add)
if [ -z "$2" ]; then
usage >&2
exit 1
fi
tmpfile=$(mktemp)
crontab -l >"$tmpfile"
printf '%s\n' "$2" >>"$tmpfile"
crontab "$tmpfile" && rm -f "$tmpfile"
;;
list)
crontab -l | cat -n
;;
remove)
if [ -z "$2" ]; then
usage >&2
exit 1
fi
tmpfile=$(mktemp)
crontab -l | sed -e "$2d" >"$tmpfile"
crontab "$tmpfile" && rm -f "$tmpfile"
;;
*)
usage >&2
exit 1
esac
사용 예:
$ ./script
Usage:
./script add "job-spec"
./script list
./script remove "job-spec-lineno"
$ ./script list
1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
3 @reboot /usr/local/bin/fetchmail
$ ./script add "0 15 * * * echo 'hello world!'"
$ ./script list
1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
3 @reboot /usr/local/bin/fetchmail
4 0 15 * * * echo 'hello world!'
$ ./script remove 4
$ ./script list
1 */15 * * * * /bin/date >>"$HOME"/.fetchmail.log
2 @hourly /usr/bin/newsyslog -r -f "$HOME/.newsyslog.conf"
3 @reboot /usr/local/bin/fetchmail
답변2
현재 cron 구현은 /etc/cron.d를 지원할 수 있습니다. 여기서 작업에는 정규 시간 필드 뒤와 명령 앞에 추가 "실행" 사용자 지정이 있습니다. 따라서 일반 크론 항목처럼 해당 디렉토리에 파일을 생성하도록 인터페이스를 조정하고 다섯 번째 필드 뒤에 사용자 이름(아마도 로그인 사용자 이름에서 추출됨)을 추가하면 됩니다. 그러면 파일당 하나의 작업을 수행할 수 있습니다. :)
보고 있다man 5 crontab
https://linux.die.net/man/5/crontab
이것의 주요 문제점은 해당 디렉토리의 파일을 편집할 수 있는 사용자가 루트로 실행되는 파일을 생성할 수 있다는 것입니다. 따라서 입력의 유효성을 검사하고 계산된 사용자 이름을 생성된 파일에 강제로 기록하는 sudo를 통해 실행되는 래퍼 스크립트가 필요할 수 있습니다. 그런 다음 스크립트에서 작업을 안전하게 수행하고 있는지 확인해야 합니다(예: $PATH 등을 신뢰하지 않음).
PS, 쉘 스크립트에서:getent passwd $(</proc/self/loginuid)
솔직히, 사용자가 cron 시간 형식을 이해하도록 하려는 경우 사용 방법을 가르치는 데 몇 초를 추가로 소비하는 것은 그리 어렵지 않습니다 crontab -e
( $EDITOR
vi가 너무 끔찍한 경우 설정).
답변3
cron 항목을 원하는 경우:
0 * * * * my_script
그런 다음 CASE 문에서 첫 번째 매개 변수가 SWITCH인 "cron_mgmt"와 같은 cron 관리 기능에 대해 별도의 이름을 고려하는 것이 좋습니다.
cron_mgmt () {
case $1 in
add ) ... ;;
list ) ...;;
remove ) ...
help ) ...
* ) echo "You need help. Here it is"
cron_mgmt help
;;
esac
}
답변4
자신만의 인터페이스를 출시하는 대신 단순하게 유지하세요. 특정 일정에 따라 크론 작업을 설치하려면 특정 디렉터리에 배치하세요. 제거하려면 디렉터리에서 삭제하세요. 사용자에게 이 작업을 수행하기 위한 도구를 제공할 필요는 없으며 작업을 어느 디렉터리에 넣을지 알려주기만 하면 됩니다.
이는 대부분의 Linux 배포판이 개별 패키지로 설치할 수 있는 시스템 크론 작업을 관리하는 방법입니다. Debian, Fedora, Arch Linux 및 기타 운영 체제는 모두 run-parts
특정 디렉터리에서 스크립트를 하나씩 실행하는 작업을 수행하는 도구를 제공합니다. 구현마다 run-parts
스크립트에 허용되는 파일 이름에 대한 규칙이 다릅니다. 이에 의존하고 싶지 않다면 직접 출시할 수 있습니다.
for x in /path/to/daily-jobs/*; do
if [ -x "$x" ]; then
case "${x##*/}" in
*[!-0-9A-Z_a-z]*) :;; # skip file names containing "weird" characters
*) "$x";;
esac
fi
done
사용자가 자신의 일정을 지정하도록 하려는 경우 이 접근 방식은 작동하지 않습니다. 새 작업이 제출될 때마다 crontab 파일을 다시 작성해야 합니다. 할 수는 있지만 안정적으로 설정하는 것은 복잡합니다. 그러나 사용자가 자신의 일정을 지정할 수 있다면 상단에 다른 인터페이스나 crontab -e
백그라운드에서 호출되는 GUI를 추가할 이유가 없습니다 .crontab -e