
起動時に実行され、定期的に実行されるbashスクリプトを作成します。
0 * * * * my_script
私はユーザーがcronジョブを実行して追加しmy_script add 0 * * * *
、ジョブを実行してリストを表示し、my_script list
コマンドmy_script remove job_number
出力にジョブ番号をリストしてジョブを削除できるようにユーザーが設定できるようにしたいと思いますmy_script list
。
crontabファイルを別々に管理できる場合は簡単です。しかし、crontabにはユーザーごとに1つのファイルしかありません(そうでない場合は教えてください)。もちろん、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をサポートできます。ここでの作業には、通常の時間フィールドの後ろとコマンドの前に追加の「実行」カスタマイズがあります。したがって、通常のクローンエントリのように、そのディレクトリにファイルを生成するようにインターフェイスを調整し、5番目のフィールドの後にユーザー名(おそらくログインユーザー名から抽出されたもの)を追加するだけです。これにより、ファイルごとに1つの操作を実行できます。 :)
見ているman 5 crontab
https://linux.die.net/man/5/crontab
これの主な問題は、そのディレクトリ内のファイルを編集できるユーザーがrootとして実行されるファイルを作成できることです。したがって、入力を検証し、計算されたユーザー名を生成されたファイルに強制的に書き込む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
でスクリプトを1つずつ実行するためのツールを提供します。実装ごとに、スクリプト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