转载一篇关于Cron的英文美文

Basic Linux task scheduling with cron

Sometimes you want to run commands nightly or weekly. You could just log in and run them yourself, but scheduling those tasks with cron is less hassle in the long run.


What is cron?

Behind the scenes, your VPS runs maintenance scripts on regular schedules. Some run nightly, some weekly, some might even run every five minutes. The scheduling for those tasks is done through a system called "cron". Most of the configuration for cron scheduling is done through files and directories that are fairly accessible.

If you want to run your own tasks on your VPS on regular schedules, you can use cron to do it. In this article we start off with the simplest approach, the cron directories.

Convenient directories

The most common schedules are pretty easy to use since they just involve picking the right directory. Over in /etc you should find several directories that start with the word "cron". The ones we want to look at right now are the ones that end with periods of time, like:

cron.daily
cron.hourly
cron.monthly
cron.weekly

The periods of time at the end of the names correspond to what they would describe in English. Any script put inside one of those directories will be run as often as the directory says it will. If a script is in "cron.weekly", for example, it will be run once a week.

You could put a symlink to a command inside a cron directory, but you usually want to pass at least some options to the command to be run, or may want to run a sequence of commands at one time (like piping the output of one command to another, or writing the output to a log). So most of the time the file you want to put into a cron directory is a script that runs your command or commands.

Basic scripting

Luckily that "script" thing I mentioned can be easier than it sounds too. We won't go into great depth about it here, but a basic shell script template looks like:

#!/bin/sh

first command
second command
third command
and so on

The first line describes the environment that will be used to run the script — the "shell". The "#!" tells the system you're describing the shell, and the rest of it is the command that runs the shell itself. You'll usually be fine just using "#!/bin/sh" like we did in the template.

The rest of the script is a list of the commands you want to run, as if you were typing them into the command line, one after the other.

If you wanted to run a couple custom programs, for example, your script could look like:

#!/bin/sh

/usr/local/bin/myprog --option andstuff
/opt/otherprog/bin/runthistoo >> stuff.log

This type of simple script is commonly called a "wrapper", since it wraps the commands you really want to run inside a script that can be easily called by other programs like cron. A wrapper can also be useful if you have a set of commands you commonly run together — just put them inside a wrapper, then you only need to type the name of the script to launch them all.

Script permissions

The final step when creating a script for cron to run is to tell the system the script is allowed to, well, be a script. To do that we need to give the script "execute permission".

Since cron runs as root, it's only really necessary to grant execute permission to "user" — the owner of the script. This can be done with the command:

chmod u+x scriptname

Replace "scriptname" with the name of your script, of course.

Summary

If you just need to use one of the basic scheduling intervals, then that's really all you need to know. It's as easy as putting the command you want to run inside a script, and putting that script into the appropriate cron scheduling directory.

You may need something more complex though, like running a script every half hour or having it run biweekly. For that we can move on to the next article in this series, which discusses more fine-grained task scheduling using the /etc/cron.d directory.

  • -- Jered
  • Fine-grained task scheduling with cron.d

    If you need more control over scheduling jobs than using the standard intervals like hourly and monthly, you can put a file in cron.d and tell it exactly how often to run.


    Fine-grained control: cron.d

    We've talked about using basic cron directories to run tasks on a standard schedule, but what if you want a schedule that's a bit less standard? What if you want to run a script every five minutes, or only run it on Tuesdays and Thursdays at 3am? You can do that (and more) with a bit of work.

    Instead of using one of the preset schedules you can set your own schedule for a script by adding a specially-formatted file to the /etc/cron.d directory.

    Checking the time

    Before you set up those more specific schedules it helps to know what time your VPS thinks it is. Your VPS is most likely using UTC as its time zone, but since it's possible to change that let's look at a simple way to check the time:

    $ date
    Thu Jul 22 10:29:37 UTC 2010

    The basic "date" command will return the current date and time on your VPS along with its time zone. Compare the time when you run the "date" command to your local time, and you can take that time difference into account when creating your own schedules.

    If it's 6:29am when you run "date" and the VPS reports that it's 10:29am, then you know your VPS time runs four hours ahead of your local time. If you want to set a script to run every night at midnight, then you'll know that when it's midnight your time it will be 4am on your VPS.

    The cron.d format

    When setting up a schedule using cron.d the file needs to be in a specific format. An entry in a cron.d file will look something like:

    42 4 1 * * root run-parts /etc/cron.monthly

    You can have several of these lines in each file but it's usually a good idea to split distinct tasks into different files to keep things organized.

    The cron.d entry above can be broken down into three parts: the schedule (the first part, "42 4 1 * *"), the user ("root"), and the command ("run-parts /etc/cron.monthly").

    Let's look at each of those three components in more detail.

    Schedule

    The first part (those first five figures) is where the schedule is set. Those numbers and asterisks represent units of time. For the example above, this part:

    42 4 2 * *

    can be read as:

    42: The 42nd minute
    4:  Of the 4th hour
    2:  of the 2nd day
    *:  of any month
    *:  on any day of the week

    Or, more briefly: The second day of every month at 4:42am.

    Schedule components

    When you have the order down the entry gets easier to read. That order, from left to right, is:

    The minute on the clock (0-59)
    The hour on a 24-hour clock (0-23)
    The day of the month (1-31)
    The month of the year (1-12)
    The day of the week (0-7), where 0 is Sunday, 6 is Saturday, and 7 is Sunday again

    An asterisk (the "*" character) tells cron to match any possible entry for that field. So an asterisk in the "month" field means that the scheduled command will run no matter what month it is. Think of the asterisk as meaning "every", so an asterisk in the "month" field means "every month".

    So looking at that order again, setting up a schedule that will run on the 20th of every month at 3:55pm would look like:

    55 15 20 * *

    The minute, then the hour, then the day of the month are specified, and then asterisks for the month and the day of the week mean the schedule will run no matter what the month or the day of the week may be.

    Getting specific

    When cron checks a schedule it compares the current time and date to the values in the schedule. Every part of the time and date have to match before the schedule will be run (with one exception, noted below), so pay careful attention to how specific you get in a schedule. For example, this:

    15 13 * * *

    means "run at 1:15pm every day", but this:

    15 13 * * 2

    means "run at 1:15pm every Tuesday", and this:

    15 13 29 2 *

    means "run at 1:15pm on the 29th of February".

    Getting less specific

    You run into a special case when you specify both "day of month" and "day of week". When both the day of the month and the day of the week are specified the schedule will match if either is true, whereas when you compare any other scheduling fields they only match if both are true. So this schedule:

    15 13 29 2 2

    means "run at 1:15pm on the 29th of February as well as every Tuesday that falls in February".

    In other words, the two "day" fields complement each other. Take out "day of month" or "day of week" and every entry narrows down the window when the schedule will run, but if you add the other "day" field as well you actually wind up adding to that window. It's a useful exception, but still potentially confusing if you don't watch out for it.

    (Thanks to Scott Gilbert for pointing out this exception.)

    Using ranges

    Entries can also be stated as a range, as in "1-5" for 1 through 5. They can also be a list of numbers separated by commas (but no spaces), as in "1,3,5".

    All these ranges and things mean that you can set up any kind of schedule you can think of, so long as you can figure out how to specify it. If you want a command to run every half hour between midnight and 5am on weekdays, that schedule would look like:

    0,30 0-5 * * 1-5

    The first entry, "0,30" will be a match every time the clock hits the hour or the half hour. The "0-5" specifies midnight (0) through 5am (5). The next two asterisks tell the schedule to run regardless of what day of the month or what month of the year it is. And then the final "1-5" tells the schedule to run only on days 1 (Monday) through 5 (Friday) — weekdays.

    Stepping

    With a better idea of how to read the cron schedule, there's one more scheduling trick we'll cover: stepping.

    */5 * * * *

    When you specify a slash then a number after a cron schedule entry, that tells cron to only consider it a match when the value in that field is divisible by the number (the "step") after the slash. To put it a little plainer, "*/5" means "any number that can be divided evenly by 5". To state it even more simply, "every 5 minutes".

    Another way to write that would be:

    0,5,10,15,20,25,30,35,40,45,50,55 * * * *

    Not as pretty as "*/5", eh?

    You can combine ranges and steps too:

    30 9-18/2 * * 1-5

    That schedule would run at the thirty-minute mark, but only every other hour between 9am and 6pm on weekdays. The hours that would match would be 10, 12, 14, 16, and 18.

    Once you have the scheduling down you've taken most of the mystery out of cron.d. The rest of it is much easier.

    User

    The next entry in a cron.d line is the user that will own the process when it runs. So for the line:

    42 4 1 * * root run-parts /etc/cron.monthly

    The "root" entry that follows the schedule tells cron that the command will be run as root.

    Command

    And finally, the rest of the cron.d line will be the command that will be run, along with its options. So in the example above, cron runs "run-parts /etc/cron.monthly".

    As it happens, that's the command that runs the scripts in /etc/cron.monthly every month. If you hunt that cron.d entry down on your system (usually in /etc/crontab) you can edit it to change on what time of day, or day of the month, cron will run its monthly scripts. The entries for the daily and hourly cron directories are similar.

    Summary

    A whole new world of task scheduling has opened to you. So long as you can get the numbers and asterisks right, the rest should fall into place. You can also now look at the cron.d files that software packages have installed and tell what kinds of background tasks are being run by those programs, and when.

    There's one other way to approach task scheduling with cron, and that's the crontab. It's similar to cron.d but the access is a bit different. It can be handy to know about because there are still some software packages that set up crontab entries, and because crontab makes it easier to handle multi-user task scheduling. We'll talk about the crontab in the next articlein this series.

    Multi-user task scheduling with crontab

    The crontab works much like cron.d, just with its own command for access and more flexibility when you want multiple users setting their own schedules.


    Oldie but goodie: crontab

    There's one more approach that can be taken when scheduling jobs with cron, and that's the "crontab". The crontab is the oldest and most standard approach to scheduling with cron, so you'll occasionally run into a package that installs a crontab entry. Using crontab can also provide a convenient method of allowing users to schedule events in cron without needing access to a file in one of the /etc/cron.* directories.

    The crontab uses a scheduling entry format similar to what's used in /etc/cron.d. If you're not familiar with that format, you should go back to the previous article in this series to read up on cron.d and how it schedules tasks.

    The crontab is something you'll typically access on a per-user basis.

    Viewing the crontab

    To view the crontab for the current user, run the crontab command with the "-l" option:

    crontab -l

    If you get a "no crontab" response, then you don't have a crontab set up for that user.

    If you do see a crontab listing, you'll notice that each line will look an awful lot like the format we used for files in /etc/cron.d.

    14 10 * * * /usr/local/bin/anotherprogram --option

    The main difference is that there is no "user" field in crontab entries, since those are already set to run as the user that owns that crontab. So the first five entries in the line are still for scheduling, and the rest of the line is the command or script to be run.

    Editing the crontab

    To edit your crontab, use the "-e" option:

    crontab -e

    This will launch your default editor and drop you into a file that will either be blank or start with a commented-out line (a line starting with the "#" character) that lists the order of schedule entries. Once you make the changes you want (either editing existing lines or adding new ones), just save the file and it will be written to the crontab.

    Working with other users' crontabs

    As root, or with sudo, you can list or edit other users' crontab entries. This is done with the "-u" option, followed by the username, then the option telling crontab what you want to do:

    sudo crontab -u demouser -l

    The above command would list the crontab entries for user "demouser".

    Who can use crontab

    In order for a user to create their own crontab and have cron follow its schedule, the user has to belong to the "crontab" group.

    sudo /usr/sbin/usermod -a -G crontab demouser

    Similarly, to remove a user's access to the crontab you can remove them from the crontab group. Unfortunately removing groups from a user isn't quite as simple, since you have to pass usermod the full list of groups you want the user to be a member of. By omitting the crontab group from the list, the user is removed from that group. Use the "id" command to get a list of a user's current groups, like so:

    $ id -nG demouser
    demouser wheel crontab www-data
    $ sudo /usr/sbin/usermod -G demouser,wheel,www-data demouser

    The "main" crontab

    One more note about the crontab is that there's a "main" crontab file at:

    /etc/crontab

    This file usually contains the schedules for the periodic cron directories (cron.hourly, cron.weekly, etc.). The only difference between this file and a user's crontab entry is that the crontab file includes the user the command will run as, similar to an entry in /etc/cron.d.

    Bonus command: at

    One extra command we'll mention is the "at" command. Where cron handles repeating schedules, the "at" command can be used for one-shot schedules. You might need to install the "at" package, since not all distributions include "at" these days.

    at 4:30pm August 12

    The at command is wonderfully flexible in terms of how you specify the time, so long as the time precedes the date. If it were Monday April 4, the following commands would all schedule a command to run on Tuesday April 5 at 2pm:

    at 2pm tomorrow
    at 2pm +1 day
    at 14:00 April 5
    at 2:00pm Tuesday

    Once you've established the time at which the command will run, at will ask for the command (or commands) to be scheduled. Enter the commands you want to run as if you were typing them at the command line. When you're done entering commands, type control-D (that's holding down control and then D) to tell it the input is complete.

    To see what jobs have been scheduled with at, run:

    atq

    You will see a list of job numbers and the commands each job will run. You can delete a pending at job with the "atrm" command, with the job number as the argument.

    The at command is handy when you just need to set up a quick one-time scheduled command, like restarting a busy web server in the middle of the night following a configuration change.

    Summary

    You should now have a good grasp of how to schedule tasks in Linux. There are more options available when scheduling with cron (including keywords like "@hourly" and "@reboot"), so if you find that you need even more flexibility it could be worth delving deeper into cron's documentation. There are also cron supplements out there like "anacron" (which is good for scheduling jobs on machines that won't necessarily be running all the time, like workstations). Basically, whatever you want to schedule, you can. At worst it's a matter of working out a weird string of numbers and asterisks to tell cron exactly when you had in mind.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值