Cron jobs e horários aleatórios, dentro de determinadas horas


99

Preciso executar um script PHP 20 vezes por dia em horários completamente aleatórios. Eu também quero que ele funcione apenas entre 9h e 23h.

Estou familiarizado com a criação de tarefas cron no Linux.


1
A questão não está muito bem colocada. Em última análise, você deseja distribuir 20 pontos no eixo do tempo entre 9h e 11h. Mas existem restrições quanto à diferença de tempo mínima? É aceitável não fazer nada entre 9h e 10h30? A única maneira de fazer isso de maneira aceitável parece ser a ideia de Klaus: selecione 20 vezes às 09:00, o que permite que você cumpra qualquer restrição que possa ter, e agende as coisas com "at".
David Tonhofer

Respostas:


37

Se eu entendi o que você está procurando, você precisará fazer algo um pouco confuso, como ter um cron job que executa um script bash que randomiza os tempos de execução ... Algo assim:

crontab:

0 9 * * * /path/to/bashscript

e em / path / to / bashscript:

#!/bin/bash

maxdelay=$((14*60))  # 14 hours from 9am to 11pm, converted to minutes
for ((i=1; i<=20; i++)); do
    delay=$(($RANDOM%maxdelay)) # pick an independent random delay for each of the 20 runs
    (sleep $((delay*60)); /path/to/phpscript.php) & # background a subshell to wait, then run the php script
done

Algumas notas: esta abordagem é um pouco desperdiçadora de recursos, pois dispara 20 processos em segundo plano às 9h, cada um dos quais espera por um número aleatório de minutos (até 14 horas, ou seja, 23h), em seguida, inicia o script php e saídas. Além disso, como ele usa um número aleatório de minutos (não segundos), os horários de início não são tão aleatórios quanto poderiam ser. Mas $ RANDOM só sobe para 32.767, e há 50.400 segundos entre 9h e 23h, seria um pouco mais complicado randomizar os segundos também. Finalmente, como os horários de início são aleatórios e independentes um do outro, é possível (mas não muito provável) que duas ou mais instâncias do script sejam iniciadas simultaneamente.


2
Você pode tornar as atribuições aritméticas mais legíveis largando o cifrão e movendo os parênteses duplos para a esquerda (por exemplo, ((maxdelay = 14 * 60))ou ((delay = $RANDOM % maxdelay))). O sleepargumento ainda precisa ser do jeito que você tem (embora você possa adicionar espaços, se desejar).
Pausado até novo aviso.

Isso funcionou para mim também. Meu script bash personalizado é parecido com o abaixo sleep $[ ( $RANDOM % 60 ) + 1 ]s && some_script.sh
Shyam Habarakada,

Estou faltando alguma coisa ou o atraso máximo deve ser definido como maxdelay = $ ((14 *
60/20

@jenishSakhiya Os atrasos aleatórios para cada uma das 20 execuções são absolutos (bem, começando às 9h), não em relação a outra corrida. Ou seja, se um dos atrasos aleatórios chegar a 13 horas, isso significa que ele será executado às 22h (13 horas após as 9h), e não 13 horas depois de qualquer uma das outras execuções.
Gordon Davisson

138

Sim, sim, a pergunta tem mais de um ano, mas talvez eu possa acrescentar algo útil:

Como cron algo em um deslocamento aleatório 20 vezes por dia entre 9h e 23h? Isso é meio complicado no cron, porque você divide 14 horas por 20 tempos de execução. Eu não gosto muito das outras respostas porque elas requerem a escrita de um script bash wrapper para seu script php.

No entanto, se você me permitir a liberdade de diminuir a restrição de tempo e frequência para 13 vezes entre 8h30 e 23h09, isso pode resolver o problema, e tudo dentro dos limites do seu crontab:

30 8-21/* * * * sleep ${RANDOM:0:2}m ; /path/to/script.php

$ {RANDOM: 3: 2} usa o $ RANDOM do bash que outras pessoas mencionaram acima, mas adiciona o fatiamento do array do bash. Como as variáveis ​​bash não são digitadas, o número pseudoaleatório de 16 bits com sinal fica truncado para os primeiros 2 de seus 5 dígitos decimais, dando-lhe uma linha sucinta para atrasar seu cronjob entre 10 e 99 minutos (embora a distribuição seja tendenciosa para 10 a 32).

O seguinte também pode funcionar para você, mas eu descobri que é "menos aleatório" por algum motivo (talvez a Lei de Benford seja acionada pela modulação de números pseudo-aleatórios. Ei, eu não sei, fui reprovado em matemática ... A culpa é disso no bash!):

30 8-21/* * * * sleep $[RANDOM\%90]m ; /path/to/script.php

Você precisa renderizar o módulo como '\%' acima porque o cron (bem, pelo menos Linux 'vixie-cron') termina a linha quando encontra um '%' sem escape.

Talvez você possa obter as 7 execuções de script restantes adicionando outra linha com outro intervalo de 7 horas. Ou relaxe sua restrição para correr entre 3h e 23h.


4
Eu gosto da resposta tardia. Mas se você está tentando gerar um número inteiro aleatório distribuído uniformemente no intervalo de 10 a 99, e a saída de RANDOM é de 0 a 32.767, por que não faria isso $[(RANDOM/368)+10]?
jsdalton

3
@jsdalton: O operador de módulo não seria melhor? $((RANDOM % 90 + 10))Teste:for i in {0..9999}; do echo $((RANDOM % 90 + 10)); done | sort | uniq -c
geon

5
Em muitos sistemas cron não usa o bash por padrão, então ele poderia ser melhor para evitar a Bashismo $RANDOM: sleep $(( $(od -N1 -tuC -An /dev/urandom) \% 90 ))m.
pabouk de

9
Certifique-se de que crontab está usando bashantes de usar $RANDOM. Se tiver vixie-cron(parece ser o meu caso no Ubuntu), você pode adicionar SHELL=/bin/bashao topo. Existem mais alternativas para outras versões do cron aqui: superuser.com/a/264541/260350
DaAwesomeP

1
Quando uso a primeira sugestão acima, recebo crontab: errors in crontab file, can't install. Do you want to retry the same edit?ajuda
Seano

72

Então, estou usando o seguinte para executar um comando entre 1h e 330h

0 1 * * * perl -le 'sleep rand 9000' && *command goes here*

Isso tem cuidado de minhas necessidades aleatórias para mim. Isso dá 9000 segundos == 150 minutos == 2,5 horas


8
:: MindBLOWN :: outro lugar obscuro para usar um pouco de perl.
Mark Carpenter Jr,

Esta é definitivamente a resposta mais limpa
Enrico Detoma

No entanto, isso é um tanto ineficiente, pois você está criando muitos processos.
kahveciderin

21

Cron oferece um RANDOM_DELAY variável. Veja crontab(5)para detalhes.

A variável RANDOM_DELAY permite atrasar o início da tarefa por uma quantidade aleatória de minutos com o limite superior especificado pela variável.

Isso é visto comumente em anacron empregos, mas também pode ser útil em a crontab.

Você pode precisar ter cuidado com isso se tiver alguns trabalhos que são executados em granularidade fina (minuto) e outros que são grosseiros.


Eu adoraria usar a variável RANDOM_DELAY, mas não consigo encontrar nenhuma dica na página de manual do crontab (5) no Ubuntu 14.04.4 LTS.
Exocom

Isso é lamentável. Eu me pergunto se não há suporte lá. Eu vejo isso documentado naquela página de manual no Centos 7 e Arch Linux.
Micah Elliott

9
esta parece ser a resposta correta, mas você pode dar um exemplo?
chovy

14
Observe que RANDOM_DELAYé estabelecido uma vez e permanece constante durante todo o tempo de execução do daemon.
Maciej Swic

5
A RANDOM_DELAYbandeira é um recurso do cronie-crond enquanto o Ubuntu parece estar em execução, vixie-cronmas não tem essa bandeira.
kravietz

7

Meu primeiro pensamento seria criar um cron job lançando 20 agendados aleatoriamente em jobs. O atutilitário (http://unixhelp.ed.ac.uk/CGI/man-cgi?at) é usado para executar comandos em um horário especificado.


Um exemplo de uso de é aqui: stackoverflow.com/a/6136145/803174
Kangur

6

Acabei usando sleep $(( 1$(date +%N) % 60 )) ; dostuffs(compatível com bash & sh)

O prefixo 1 é para forçar a interpretação NON base 8 da data +% N (por exemplo, 00551454)

Não se esqueça de escapar% usando \% em um arquivo crontab

* * * * *  nobody  sleep $(( 1$(date +\%N) \% 60 )) ; dostuffs 

2
Se alguém se perguntar, como eu:% N fornece nanos atuais, mas algumas páginas de manual não têm informações sobre isso. Esta é uma solução muito inteligente para pessoas que precisam apenas de "alguma aleatoriedade" facilmente por comando.
Thorsten Schöning,

Além das advertências já abordadas em outro lugar, isso só funcionará se você tiver GNU date(o que você provavelmente tem na maioria dos Linuxes, mas não no Busybox, MacOS padrão ou várias outras plataformas derivadas de BSD).
tripleee

4

A solução de al-x não funciona para mim, pois os comandos crontab não são executados em bash, mas em sh, eu acho. O que funciona é:

30 8 * * * bash -c "sleep $[RANDOM\%90]m" ; /path/to/script.py

Eu tentei de tudo e ainda não funcionou para mim. Você postou explicou o porquê, obrigado!
marlar

$[ ... ]é uma sintaxe obsoleta desde waaaay de volta; para qualquer coisa deste milênio, você prefere $((RANDOM\%90))mqual é a sintaxe compatível com POSIX (mas RANDOMé claro que ainda é apenas Bash).
tripleee

1

at -f [file] [timespec]

ou

echo [command] | at [timespec]

ou

at [timespec]... e especificações interativas como scripta gravação de.

Comando

Em executa o texto fornecido em stdin ou no arquivo especificado por -f [file].

Timespec

Aqui está a [timespec] gramática . Pode ser algo como:

  • De tempo de 24 horas como int quatro dígitos, por exemplo 0100, 2359,1620
  • now + 10 minutes
  • 2071-05-31 - 5 hours 12 minutes UTC

Se você estiver especificando explicitamente o fuso horário, algumas versões do timespec podem permitir apenas UTCo argumento opcional de fuso horário.

Exemplo

cat script.sh | at now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

at -f script.sh now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

Experimente...

Você pode testar a análise bash fazendo uma pré-pendente echoe escapando do |(tubo).

echo cat script.sh \| at now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

echo at -f script.sh now + $(($RANDOM % 10)) hours $(($RANDOM % 60)) minutes

Para ver os trabalhos agendados, use atqe o conteúdo do trabalho (variáveis ​​de ambiente, configuração e comando / script) com at -c [jobid].

Nota

O sistema é parte do cron e o prompt interativo realmente captura todo o estado atual do seu shell, para que você possa executar comandos sem especificar caminhos absolutos.


0

Para quem pesquisou o caminho até aqui:

Se você estiver usando anacron (desktop e laptop Ubuntu), você pode editar

/etc/anacrontab

e adicione

RANDOM_DELAY=XX 

Onde XX é a quantidade de minutos que você deseja atrasar o trabalho base.

O Anacron é como o cron, mas não espera que seu computador funcione 24 horas por dia, 7 dias por semana (como nossos laptops) e executará os scripts que perdeu porque o sistema estava fora do ar.


0

Você pode tentar com este exemplo usar tempos aleatórios antes de executar o comando:

#!/bin/bash
# start time
date +"%H:%M:%S"

# sleep for 5 seconds
sleep $(shuf -i 1-25 -n 1)
# end time
date +"%H:%M:%S"

0

Que tal criar um script que reescreve o crontab todos os dias?

  1. Leia crons atuais (A)
  2. Escolha tempos aleatórios (B)
  3. Reescrever crons anteriores (A), adicionar novos crons aleatórios (B)
  4. Certifique-se de adicionar ao cron para executar este script em primeiro lugar.

2
Não contorne o sistema de reputação postando comentários como respostas. No entanto, seu comentário parece bom o suficiente para ser realmente uma resposta. Eu recomendo remover " Eu não tenho representante para adicionar um comentário, mas ".
Ted Lyngmo

1
Acabei de revisar esta resposta e perdi a parte em que você está fazendo uma pergunta de volta no final (trabalho desleixado da minha parte). Não faça perguntas nas respostas. Poste sua própria pergunta para perguntas que você tem. Transformei sua semi-pergunta em algo que poderia passar por uma resposta.
Ted Lyngmo

1
Entendi! THX. Serei mais cuidadoso da próxima vez, nenhuma má intenção foi intencional.
melofellow

1
Tenho certeza de que você não teve más intenções e não precisa ser excessivamente cuidadoso. Você delineou uma possível solução - e tropeçou um pouco no final. Não se preocupe!
Ted Lyngmo

0

Sei que é um segmento mais antigo, mas quero adicionar uma coisa relacionada a valores aleatórios que uso muito. Em vez de usar a variável $ RANDOM com um intervalo fixo e limitado, geralmente crio valores aleatórios de intervalo arbitrário no shell com

dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -N4 -t u4 -A none

então você pode fazer, por exemplo,

FULLRANDOM=$(dd if=/dev/urandom bs=4 count=1 2>/dev/null | od -N4 -t u4 -A none)

e superar algumas das restrições que foram discutidas neste tópico.


1
Bem-vindo ao SO. Bem, discussão antiga ou não, isso me levou a ~$info dde posso entender o que está acontecendo no lado esquerdo |, mas não consigo distinguir o lado direito. Então, para mim e outros interessados ​​na overcoming some restrictionsgeração de valor aleatório, por que não reservar um momento para explicar o RHS e fazer um argumento mais forte para usar sua abordagem. A profundidade da explicação deixa as pessoas confortáveis ​​com o processo que você sugere e seus benefícios. Obrigado.
Chris

Ah ok. od aka "octal dump" pega um arquivo ou stdin e despeja os dados binários em uma forma legível por humanos. Queremos que nosso número seja mostrado como um decimal sem sinal (-t u4) e não queremos o índice de endereço (-A nenhum). O -N4 é redundante porque pegamos apenas 4 bytes, mas também não faz mal. Espero que isso explique ...
MLP
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.