bashでcronジョブを自動登録する (Linuxバッチでcrontabを編集)
Linux上で,スケジュールされたタスクを実行するためには,cronが必要。
そのcronタスク設定操作を自動化するには,どうしたらよいか?
本記事では,以下の点を扱う。
crondのインストール(手動)
crontabが入ってても,crondが無かったりする。
crondのインストール状況の確認方法:
/etc/init.d/crond status
※または /sbin/service crond status
もし無効であれば,crondをインストールする必要がある。
crondのrpm(vixie-cron)をダウンロードして取得
http://whatislinux.net/rpm/vixie-cron...
RPM: vixie-cron-4.1-76.el5.i386.rpm
インストール
rpm -ivh vixie-cron-4.1-76.el5.i386.rpm
インストールされたことを確認
rpm -qa | grep vixie-cron
これで,以下のファイルやフォルダが生成される。
- /etc/init.d/crond (起動スクリプト)
- /var/spool/cron (ジョブ定義ファイルの設置ディレクトリ)
なお,アンインストールは下記。
rpm -e vixie-cron-4.1-76.el5.i386
削除時はrpmの拡張子を含めない点に注意。
crondのインストール(自動)
前項のインストールを,シェルで自動化しよう。
インストール用のシェル:
rpmと同一フォルダに,install_crond.sh
#!/bin/sh # rpmのパス rpm_file="vixie-cron-4.1-76.el5.i386.rpm" ## インストール実行 # 既にインストールされているかどうかで分岐 # rpmのリストの行数が0行より大きいかどうかを判定 if [ `rpm -qa | grep vixie-cron | wc -l` -gt 0 ] ; then # インストール済みだった場合 echo "already installed." else # 無かった場合 echo "not yet installed. executing install..." # インストール実行 rpm -ivh ${rpm_file} fi ## インストールが完了していることを確認 # RPMの数 echo "number of rpm:" [ `rpm -qa | grep vixie-cron | wc -l` -gt 0 ] && echo "OK" || echo "NG" # 起動スクリプトがあるか echo "init script:" [ -f /etc/init.d/crond ] && echo "OK" || echo "NG" # フォルダがあるか echo "/var/spool/cron :" [ -d /var/spool/cron ] && echo "OK" || echo "NG" echo "install script finished."
アンインストール用のシェル:
#!/bin/sh # rpmの識別キー rpm_key="vixie-cron-4.1-76.el5.i386" ## アンインストール実行 # 既にインストールされているかどうかで分岐 if [ `rpm -qa | grep vixie-cron | wc -l` -gt 0 ] ; then # インストール済みだった場合 echo "already installed. executing uninstall..." # アンインストール実行 rpm -e ${rpm_key} else # 無かった場合 echo "not yet installed." fi ## アンインストールが完了していることを確認 # RPMの数 echo "number of rpm:" [ `rpm -qa | grep vixie-cron | wc -l` -eq 0 ] && echo "OK" || echo "NG" # 起動スクリプトがあるか echo "init script:" [ ! -f /etc/init.d/crond ] && echo "OK" || echo "NG" # フォルダがあるか echo "/var/spool/cron :" [ ! -d /var/spool/cron ] && echo "OK" || echo "NG" echo "uninstall script finished."
cronにジョブ登録(手動)
rootユーザの場合,/var/spool/cron/root というファイルの中に,1行ずつジョブを記述する。
そうすると,登録されたジョブはcronによって「rootユーザとして」実行されることになる。
http://q.hatena.ne.jp/1139540811#
- /etc/crontab:システムジョブ(デイリーログローテーションやデイリーバックアップなど)で使用するもので、全てroot権限で実行されます。
- /var/spool/cron/:ユーザジョブと言われるもので、許可された各ユーザごとのcronが入ります。実行ユーザは各ユーザ
ここでは,
「毎分,/tmp内に,現在時刻をファイル名に持つようなファイルを作成する」
というジョブを登録する。
/var/spool/cron/root
* * * * * touch /tmp/hoge_`date +\%Y\%m\%d\%H\%M\%S`
「*」は順に,分,時,日,月,曜日を表す。
はまりやすい点は2つある。
(1)各ジョブの行の末尾には改行(LF)が必要。
manpage of Ubuntu
http://manpages.ubuntu.com/manpages/g...
- cronではcrontabの各エントリの末尾に改行文字があることが必要になる
- 改行文字で終わっていないコマンドは絶対に実行されない。
- 間違いを防ぐためには、crontabの末尾に必ず空行を入れるようにするのが一番よい。
(2)ジョブとして実行したいコマンドの「%」は,エスケープする必要がある。
crontab「第 6」フィールド中の'%'は改行として解釈される
http://d.hatena.ne.jp/turutosiya/2009...
- コマンド中にパーセント記号 (%) が バックスラッシュ (\) によってエスケープされずに置かれていると、 改行文字に置き換えられ、最初に現れた % 以降の全てのデータは 標準入力としてコマンドに送られる。
crontabのよくあるミス
http://ja.wikipedia.org/wiki/Crontab#...
- よくあるミスのひとつは、コマンド指定においてエスケープせずに「%」記号を使うことで、これはエスケープする必要がある。
※ベターなのは,crontabファイル内に直接コマンドを書かずに,シェルスクリプトを呼び出す形式にすることだ。
そのほうが変更しやすく保守性が保てる。
ジョブ定義ファイルを設置したら,crondを再起動しておく。
/etc/init.d/crond restart
これで即時,ジョブ定義ファイルがリロードされ,次の分の01秒から毎分ジョブが実行される。
cronにジョブ登録(自動)
ここが本題。
「cronにジョブを登録するコマンド」というと「crontabコマンド」がある。
crontab -e は,単に「エディタでcrontab設定ファイルを開く」コマンドでしかない。
crontab ファイル名 とすれば,ファイルからジョブを登録することもできる。
恐怖のcrontab -r. 設定ファイルはレポジトリ管理せよ
http://d.hatena.ne.jp/LukeSilvia/2008...
- crontabの定期的なバックアップ出力をcrontabしておく
- crontabへの登録内容を特定の場所に置いといて,そのファイルを編集してcrontabコマンドで読み込ませるように
Linuxのcrontabコマンドの脆弱性をつぶす
http://codezine.jp/article/detail/5360
- crontabファイルとcrontabコマンドの違い
- マニュアルページのセクション番号を付けて、設定ファイルはcrontab(5)、コマンドはcrontab(1)などと表記します。
また,下記のように直接ファイル操作する方法もある。
これだと,「同じタスクが重複して登録されないようにチェックする」など細かい操作が可能。
add_cron_job.sh
#!/bin/sh # 登録したいジョブ cron_job_line="* * * * * touch /tmp/hoge_\`date +\\%Y\\%m\\%d\\%H\\%M\\%S\`" # crontabファイル cron_file="/var/spool/cron/root" ## crontabファイル準備 # 無ければ作る [ -f ${cron_file} ] && touch ${cron_file} ## タスク登録 # 既に登録されているかどうかを判定 cron_job_line_for_grep="${cron_job_line//\\/\\\\}" if [ `grep "${cron_job_line_for_grep}" "${cron_file}" | wc -l` -eq 0 ] ; then echo "not registered yet. begin registering..." # 追記 echo "${cron_job_line}" >> "${cron_file}" else echo "already registered." fi # cron再起動 /etc/init.d/crond restart echo "registering finished."
細かな注意点をいくつか。
(bashコーディング上のポイント)
(1)""で囲まれた文字列中の``はエスケープしないと即時実行されてしまう。
→ "\`"のようにする。
(2)バックスラッシュが1個だけだと,grepは別の意味に解釈してしまう。
→"${cron_job_line//\\/\\\\}"のように全置換して2個に増やす。
(3)echo * だと,アスタリスクが「カレントディレクトリの全ファイル名」に展開されてしまう。
→echo "*" のようにくくる。
補足:cronのログのローテーション
cronのログは,/var/log/cron である。
cronに「毎分実行」のタスクが登録されていたら,cronのログは肥大化しやすくなる。
ログのローテーション設定はどうなっているか。
(1)crontab設定ファイル
/etc/crontab
SHELL=/bin/bash PATH=/sbin:/bin:/usr/sbin:/usr/bin MAILTO=root HOME=/ # run-parts 01 * * * * root run-parts /etc/cron.hourly 02 4 * * * root run-parts /etc/cron.daily 22 4 * * 0 root run-parts /etc/cron.weekly 42 4 1 * * root run-parts /etc/cron.monthly
/etc/cron.dailyフォルダ内の全タスクを実行するように設定されている。
システム設定ファイルを知ろう〜/etc/crontab〜
http://www.itmedia.co.jp/help/tips/li...
run-partsとは
http://d.hatena.ne.jp/hogem/20090331/...
指定ディレクトリ以下のスクリプトを順次実行するコマンド
(2)/etc/cron.dailyフォルダ
logrotateという名前のシェルが置いてある。
#!/bin/sh
/usr/sbin/logrotate /etc/logrotate.conf
/etc/logrotate.confという設定ファイルを参照している。
(3)/etc/logrotate.confファイル
ログのローテーション設定ファイル。
# see "man logrotate" for details # rotate log files weekly weekly # keep 4 weeks worth of backlogs rotate 4 # send errors to root errors root # create new (empty) log files after rotating old ones create # uncomment this if you want your log files compressed #compress # RPM packages drop log rotation information into this directory include /etc/logrotate.d # no packages own lastlog or wtmp -- we'll rotate them here /var/log/wtmp { monthly create 0664 root utmp rotate 1 }
/etc/logrotate.dを参照している。
(4)/etc/logrotate.dフォルダ
syslogというファイルがある。logrotateの設定ファイルの一種。
/var/log/messages /var/log/secure /var/log/maillog /var/log/spooler /var/log/boot.log /var/log/cron { sharedscripts postrotate /bin/kill -HUP `cat /var/run/syslogd.pid 2> /dev/null` 2> /dev/null || true endscript }
/var/log/cronをローテーション対象として指定している。
(※crondをインストールする前から/var/log/cronがローテーション対象になっている。)
記法は以下を参照:
logrotateによるログのローテーション
http://linux.kororo.jp/cont/server/lo...
- sharedscripts は、以降に記述された処理をワイルドカードの指定に関わらず、1度だけ実行するという宣言文です
- syslogにHUPシグナルを送り、再起動をすることで、ローテーション後に create によって作成されたファイルに正常にsyslogがログを吐き出すようにしている
syslogの保存期間を変更するには
http://www.atmarkit.co.jp/flinux/rens...
syslogについての補足。
cronは,ログを出力する際に「syslog」を使う。
(Javaアプリがログ出力のためにLog4jを使うのが標準なのと同じように,Linux上の多くのアプリケーションがsyslogを経由してログ出力する。)
syslogは,設定ファイルsyslog.confの中で,cronのログを/var/log/cronに出力するようになっている。
なので,cronのログはそこに出力される。
# Log cron stuff cron.* /var/log/cron
/etc/syslog.conf設定
http://variable.jp/linux/2007/11/etcs...