Como criar programaticamente um novo trabalho cron?

129

Quero poder adicionar programaticamente um novo trabalho cron, qual é a melhor maneira de fazer isso?

Da minha pesquisa , parece que eu poderia despejar o crontab atual e, em seguida, acrescentar um novo, canalizando-o novamente para o crontab:

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

Existe uma maneira melhor?

davidmytton
fonte
2
Sua solução parece ser boa.
Craig S
No Solaris, remova o traço do último crontab. Você pode adicionar um grep para evitar adicionar uma linha já existente.
31812 Lacroix1547
Possível duplicata Como criar um trabalho cron usando Bash
Ciro Santilli郝海东冠状病六四事件法轮功
chaves entre parênteses em vez de parênteses o farão sem gerar um processo. Certifique-se de manter espaços ao redor do aparelho, {...; }
Jay Winston

Respostas:

-25

Sempre funcionou bem para mim.

Você deve considerar um script um pouco mais sofisticado que pode fazer três coisas.

  1. Acrescente uma linha de crontab; assegurando que não existia. Adicionar quando já existe é ruim.

  2. Remova a linha do crontab. Talvez apenas avisando se não existisse.

  3. Uma combinação dos dois recursos acima para substituir a linha crontab.

S.Lott
fonte
78
Ele pergunta como e você diz a ele o que?
Cerin
1
E se o usuário ainda não tiver um crontab?
Maxim Egorushkin
132

A melhor maneira de rodar como root é soltar um arquivo no /etc/cron.d

se você usar um gerenciador de pacotes para empacotar seu software, basta colocar os arquivos nesse diretório e eles serão interpretados como se fossem crontabs, mas com um campo extra para o nome de usuário, por exemplo:

Nome do arquivo: /etc/cron.d/per_minute

Conteúdo: * * * * * root /bin/sh /home/root/script.sh

MarkR
fonte
5
Apenas verifique se a versão do cron em uso suporta o /etc/cron.d/. A maioria das distribuições modernas de Linux fazem.
Sleske 06/03/09
8
Esta é a solução mais simples e elegante. Certamente é melhor analisar e editar um crontab existente com outras entradas não relacionadas.
Cerin
13
Uma ressalva em potencial é a frequência com que o cron obtém novas adições a essa pasta (uma vez por hora). Se você espera que seu trabalho comece a funcionar imediatamente, tenha cuidado.
JonathanK
6
@ JonathanK, você sabe se o cron pode ser solicitado a verificar novamente /etc/cron.d/*? É difícil saber se algo está funcionando, se é preciso esperar uma hora para verificar!
halfer
4
como as permissões devem ser definidas para esse arquivo? chmod + x /etc/cron.d/per_minute?
giò
101

A solução do OP tem um erro, pode permitir que as entradas sejam adicionadas duas vezes, use abaixo para corrigir.

(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -
JohnZ
fonte
5
Esta é realmente uma solução melhor, se não descrita. Ele garante que o comando não seja adicionado duas vezes ao crontab.
Bufke
2
Essa dificilmente é uma boa correção para o problema de entrada duplicada. E se outra linha fosse adicionada ao crontab nesse meio tempo?
Hmn
6
Para garantir a exclusividade, logo sortantes uniq, por exemplo:(crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | crontab -
mway 21/03
6
Não há necessidade uniq. Use a -uopção em sort.
papiro 12/12
6
como evitar o crontab para o usuário quando eu editar o crontab pela primeira vez.
Wyx
23

Para adicionar algo ao cron

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

Para remover isso do cron

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

a esperança ajudaria alguém

user3865482
fonte
Isto é exatamente o que eu estava procurando, apenas acrescentaria o seguinte: | grep -v '^ #' | para filtrar os comentários
Tjunkie
2
Você realmente não precisa, 2>&1 | grep -v "no crontab"porque quando não há crontab, a linha de saída crontab: no crontab for...é enviada ao stderr. Não há razão para capturar essa saída, enviá-la para stdout e filtrá-la usando grep. Se seu objetivo é evitar ver crontab: no crontab for...em sua saída, use 2> /dev/null | sort.....
matty 2/09/16
6

Se você planeja fazer isso em um cenário de execução única, apenas para fazer algo, dê uma olhada em 'at'

Christian Witts
fonte
6

Simplesmente mude o editor para o comando tee:

export EDITOR="tee"
echo "0 * * * * /bin/echo 'Hello World'" | crontab -e
Renato Tambellini
fonte
3
Cuidado - isso limpa todas as entradas existentes.
starfry
5

Supondo que já exista uma entrada no seu crontab, o comando a seguir deve funcionar relativamente bem. Observe que a $CMDvariável está lá apenas para facilitar a leitura. A classificação antes de filtrar duplicatas é importante, porque uniqfunciona apenas em linhas adjacentes.

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

Se você atualmente possui um crontab vazio, receberá o seguinte erro no stderr:

no crontab for user

Se você quiser evitar isso, adicione um pouco de complexidade e faça algo assim:

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

A maioria das soluções aqui é para adicionar linhas ao crontab. Se você precisar de mais controle, poderá controlar todo o conteúdo do crontab.

Você pode usar a tubulação para fazer isso com bastante elegância.

Para reescrever completamente o crontab, faça

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

Deve ser fácil combinar com outras respostas descritas aqui, como

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

Ou, se você tiver o conteúdo de um arquivo, é ainda mais simples

cat <file> |crontab -
Eldamir
fonte
3

Aqui está outra maneira de uma linha, que evita duplicatas

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

E aqui está uma maneira de responder a JohnZ e evitar a no crontab for usermensagem, ou se você precisar operar em um set -euambiente de tipo e não puder fazer nada retornar uma falha (nesse caso, a 2>/dev/nullpeça é opcional):

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

Ou se você deseja dividir as coisas para que sejam mais legíveis:

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

Ou, opcionalmente, remova qualquer referência ao seu_command (por exemplo: se o agendamento foi alterado, você só deseja que ele seja programado uma vez). Nesse caso, não precisamos mais uniq(bônus adicional, o pedido de inserção também é preservado):

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 -
rogerdpack
fonte
2

O man crontab também é útil:

CRONTAB (1)

NOME

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

SINOPSE

   crontab file [-u user] - replace crontab from file

   crontab - [-u user] - replace crontab from stdin

   crontab -l [user] - list crontab for user
vitaly.v.ch
fonte
3
A parte que diz "substituir crontab de stdin" é na verdade meia resposta :-)
Grodriguez
2

Adicionando à resposta de JohnZ, aqui está a sintaxe para agendar como root se você é um sudoer:

(sudo crontab -l ; echo "0 * * * * your_command") | sort - | uniq - | sudo crontab -
BuvinJ
fonte
1
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');
RafaSashi
fonte
1

Isso verifica se o seu comando ainda não existe antes de adicioná-lo.

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

Felicidades.

Ezra Obiwale
fonte
0

Piping stdout para crontabnão instalou o novo crontab para mim no macOS, então encontrei esta solução, usando o teeeditor em um sub shell:

(EDITOR=tee && (crontab -l ; echo "@daily ~/my-script.sh" ) | uniq - | crontab -e)
Simon Hänisch
fonte
0

Se você deseja que a tarefa seja executada como usuário:

crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | crontab -

Se você deseja que a tarefa seja executada com privilégios:

sudo crontab -l | { cat; echo "@weekly what_you_want_to_execute"; } | sudo crontab -

e verifique a tarefa (com ou sem 'sudo'):

crontab -l | sed '/^$/d; /#/d'
ajcg
fonte
-1

você também pode adicionar suas tarefas ao /etc/cron.*/

vitaly.v.ch
fonte
-2

Você também pode editar o arquivo de texto da tabela cron diretamente, mas sua solução parece perfeitamente aceitável.

Alex Fort
fonte
1
Eu ficaria desconfiado disso devido a preocupações com a possibilidade de edições simultâneas causando corrupção de arquivo. O uso do comando crontab da linha de comando deve evitar esse problema.
Craig S
Craig, sem mais pesquisas, eu não teria certeza de que a versão da linha de comando é atômica e segura para as condições de corrida. Provavelmente "bastante seguro" de qualquer maneira.
tuomassalo
"Editar o arquivo diretamente" não é possível sem acesso root (desde que você possa descobrir onde está o arquivo crontab do usuário e como garantir que o daemon cron receba corretamente suas alterações), e "editar" programaticamente parece ser a pergunta. quer conselhos em primeiro lugar.
Tripleee