linux - 如何以编程方式创建新的Cron作业?

original title: "linux - How can I programmatically create a new cron job?"


Translate

I want to be able to programatically add a new cron job, what is the best way to do this?

From my research, it seems I could dump the current crontab and then append a new one, piping that back into crontab:

(crontab -l ; echo "0 * * * * wget -O - -q http://www.example.com/cron.php") | crontab -

Is there a better way?



我希望能够以编程方式添加新的cron作业,最佳方法是什么?从我的研究看来,我可以转储当前的crontab,然后附加一个新的crontab,然后将其返回给我。

这是翻译后的摘要,如果您需要查看完整的翻译,请单击“Translate”图标


所有的回答
  • Translate

    It's always worked well for me.

    You should consider a slightly more sophisticated script that can do three things.

    1. Append a crontab line; assuring that it didn't exist. Adding when it already exists is bad.

    2. Remove the crontab line. Perhaps only warning if it didn't exist.

    3. A combination of the above two features to replace the crontab line.


  • Translate

    The best way if you're running as root, is to drop a file into /etc/cron.d

    if you use a package manager to package your software, you can simply lay down files in that directory and they are interpreted as if they were crontabs, but with an extra field for the username, e.g.:

    Filename: /etc/cron.d/per_minute

    Content: * * * * * root /bin/sh /home/root/script.sh


  • Translate

    OP's solution has a bug, it might allow entries to be added twice, use below to fix.

    (crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -
    

  • Translate

    To Add something to cron

    (crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | sort | uniq | crontab -
    

    To remove this from cron

    (crontab -l ; echo "0 * * * * hupChannel.sh") 2>&1 | grep -v "no crontab" | grep -v hupChannel.sh |  sort | uniq | crontab -
    

    hope would help someone


  • Translate

    If you're planning on doing it for a run-once scenario for just wget'ing something, take a look at 'at'


  • Translate

    Simply change the editor to tee command:

    export EDITOR="tee"
    echo "0 * * * * /bin/echo 'Hello World'" | crontab -e
    

  • Translate

    Assuming that there is already an entry in your crontab, the following command should work relatively well. Note that the $CMD variable is only there for readability. Sorting before filtering duplicates is important, because uniq only works on adjacent lines.

    CMD='wget -O - -q http://www.example.com/cron.php"'
    (crontab -l ; echo "0 * * * * $CMD") | sort | uniq | crontab -
    

    If you currently have an empty crontab, you will receive the following error to stderr:

    no crontab for user
    

    If you want to avoid this, you can add a little bit of complexity add do something like this:

    (crontab -l ; echo "0 * * * * $CMD") 2>&1 | sed "s/no crontab for $(whoami)//"  | sort | uniq | crontab -
    

  • Translate

    Most of the solutions here are for adding lines to the crontab. If you need more control, you'll want to be able to control the entire contents of the crontab.

    You can use piping to do this pretty elegantly.

    To completely rewrite the crontab, do

    echo "2 2 2 2 2 /bin/echo foobar" |crontab -
    

    This should be easy to combine with other answers described here like

    crontab -l | <something> | tee |crontab -
    

    Or, if you have the contents in a file, it is even simpler

    cat <file> |crontab -
    

  • Translate

    man crontab is also useful:

    CRONTAB(1)

    NAME

       crontab - manipulate per-user crontabs (Dillon's Cron)
    

    SYNOPSIS

       crontab file [-u user] - replace crontab from file
    
       crontab - [-u user] - replace crontab from stdin
    
       crontab -l [user] - list crontab for user
    

  • Translate

    Adding to JohnZ's answer, here's the syntax to schedule as root if you are a sudoer:

    (sudo crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | sudo crontab -
    

  • Translate
    function cronjob_exists($command){
    
        $cronjob_exists=false;
    
        exec('crontab -l', $crontab);
    
    
        if(isset($crontab)&&is_array($crontab)){
    
            $crontab = array_flip($crontab);
    
            if(isset($crontab[$command])){
    
                $cronjob_exists=true;
    
            }
    
        }
        return $cronjob_exists;
    }
    
    function append_cronjob($command){
    
        if(is_string($command)&&!empty($command)&&cronjob_exists($command)===FALSE){
    
            //add job to crontab
            exec('echo -e "`crontab -l`\n'.$command.'" | crontab -', $output);
    
    
        }
    
        return $output;
    }
    
        append_cronjob('* * * * * curl -s http://localhost/cron/test.php');
    

  • Translate

    This would check to ensure that your command doesn't already exist before adding it.

    crontab -l 2>/dev/null | grep -q '/path/to/script' || echo "5 * * * * /path/to/script" | crontab -
    

    Cheers.


  • Translate

    Piping stdout into crontab didn't install the new crontab for me on macOS, so I found this solution instead, using the tee editor in a sub shell:

    (EDITOR=tee && (crontab -l ; echo "@daily ~/my-script.sh" ) | uniq - | crontab -e)
    

  • Translate

    Here's another one-liner way, that avoids duplicates

    (crontab -l 2>/dev/null | fgrep -v "*/1 *  *  *  * your_command"; echo "*/1 *  *  *  * your_command") | crontab -
    

    And here's a way to do JohnZ's answer and avoid no crontab for user message, or if you need to operate in a set -eu type environment and can't have anything return a failure (in which case the 2>/dev/null part is optional):

    ( (crontab -l 2>/dev/null || echo "")  ; echo "0 * * * * your_command") | sort -u - | crontab -
    

    Or if you want to split things up so that they're more readable:

    new_job="0 * * * * your_command"
    preceding_cron_jobs=$(crontab -l || echo "")
    (echo "$preceding_cron_jobs" ; echo "$new_job") | sort - | uniq - | crontab -
    

    Or optionally remove any references to your_command (ex: if the schedule has changed, you only want it ever cron'ed once). In this case we no longer need uniq (added bonus, insertion order is also preserved):

    new_job="0 * * * * your_command"
    preceding_cron_jobs=$(crontab -l || echo "")
    preceding_cron_jobs=$(echo "$preceding_cron_jobs" | grep -v your_command )
    (echo "$preceding_cron_jobs" ; echo "$new_job") | crontab -
    

  • Translate

    also you can add your tasks to /etc/cron.*/


  • Translate

    You could also edit the cron table text file directly, but your solution seems perfectly acceptable.