Linux / Bash, como agendar comandos em uma fila FIFO?

7

Eu quero a capacidade de agendar comandos para serem executados em uma fila FIFO. Eu não quero que eles sejam executados em um horário específico no futuro, como seria o caso do comando "at". Eu quero que eles comecem a correr agora, mas não simultaneamente. O próximo comando agendado na fila deve ser executado somente após o primeiro comando terminar a execução. Alternativamente, seria bom se eu pudesse especificar um número máximo de comandos da fila que poderiam ser executados simultaneamente; por exemplo, se o número máximo de comandos simultâneos for 2, somente no máximo 2 comandos agendados na fila seriam retirados da fila de maneira FIFO a ser executada, o próximo comando na fila restante sendo iniciado somente quando um dos atualmente 2 comandos em execução são concluídos.

Eu ouvi que o spooler de tarefas poderia fazer algo assim, mas este pacote não parece ser bem suportado / testado e não está nos repositórios padrão do Ubuntu (sendo o Ubuntu o que eu estou usando). Se essa é a melhor alternativa, me avise e usarei spooler de tarefas, caso contrário, estou interessado em descobrir qual é a melhor maneira, mais fácil, mais testada, sem erros e canônica de fazer uma coisa dessas com o bash.

ATUALIZAÇÃO:

Soluções simples como; ou & & do bash não funcionam. Eu preciso agendar esses comandos de um programa externo, quando ocorre um evento. Eu só não quero ter centenas de instâncias do meu comando em execução simultaneamente, daí a necessidade de uma fila. Existe um programa externo que acionará eventos onde posso executar meus próprios comandos. Eu quero lidar com todos os eventos disparados, eu não quero perder nenhum evento, mas eu também não quero que meu sistema trave, então é por isso que eu quero uma fila para lidar com os meus comandos disparados do programa externo.

    
por Andrei 10.04.2013 / 16:26

6 respostas

16

Spooler de tarefas:

link

link

Faz o truque muito bem. Espero que seja incluído nos repositórios de pacotes do Ubuntu.

    
por 11.04.2013 / 13:40
4

Use ;

Por exemplo: ls ; touch test ; ls

Isso listará o diretório. Somente depois que ls for executado, ele executará touch test , o que criará um arquivo chamado test. E somente depois que terminar, o próximo comando será executado. (Nesse caso, outro ls mostrará o conteúdo antigo e o arquivo recém-criado).

Comandos semelhantes são || e && .

; sempre executará o próximo comando.

&& só executará o próximo comando do primeiro sucesso retornado.
Exemplo: rm -rf *.mp3 && echo "Success! All MP3s deleted!"

|| só executará o próximo comando se o primeiro comando retornar um valor de retorno de falha (diferente de zero). Exemplo: rm -rf *.mp3 || echo "Error! Some files could not be deleted! Check permissions!"

Se você quiser executar um comando em segundo plano, anexe um e comercial ( & ).
Exemplo: make bzimage & e mp3blaster sound.mp3 e make mytestsoftware ; ls ; firefox ; make clean

Será executado dois comandos em segundo plano (neste caso, uma compilação do kernel que levará algum tempo e um programa para reproduzir algumas músicas). E nos foregrounds ele roda outro trabalho de compilação e, uma vez terminado, ls, firefox e make clean (todos sequencialmente)

Para mais detalhes, consulte man bash

[Editar após comentário]

no pseudo código, algo assim?


Program run_queue:

While(true)
{
   Wait_for_a_signal();

   While( queue not empty )
   {
       run next command from the queue.
       remove this command from the queue.
       // If commands where added to the queue during execution then
       // the queue is not empty, keep processing them all.
   }
   // Queue is now empty, returning to wait_for_a_signal
}
// 
// Wait forever on commands and add them to a queue
// Signal run_quueu when something gets added.
//
program add_to_queue()
{
   While(true)
   {
       Wait_for_event();
       Append command to queue
       signal run_queue
   }    
}
    
por 10.04.2013 / 17:00
2

A maneira mais fácil seria simplesmente executar os comandos sequencialmente:

cmd1; cmd2; cmd3; cmdN

Se você quiser que o próximo comando execute somente se o comando anterior tiver saído com sucesso, use && :

cmd1 && cmd2 && cmd3 && cmdN

Essa é a única forma básica que sei fazer o que você quer. Se você precisar de controle de tarefas (definindo vários trabalhos paralelos, etc.), poderá tentar instalar um gerenciador de filas, como TORQUE mas isso parece um exagero se tudo o que você quer fazer é lançar trabalhos sequencialmente.

    
por 10.04.2013 / 17:03
1

Você está procurando o irmão gêmeo de at : batch . Ele usa o mesmo daemon, mas em vez de agendar um horário específico, os trabalhos são enfileirados e serão executados sempre que a média de carga do sistema for baixa.

    
por 10.04.2013 / 17:24
0

Além dos sistemas de enfileiramento dedicados (como o Sun Grid Engine ) que você também pode usar localmente em uma máquina e que oferecer dezenas de possibilidades, você pode usar algo como

 command1 && command2 && command3

qual é o outro extremo - uma abordagem muito simples. Este último não fornece múltiplos processos simultâneos nem o preenchimento gradual da "fila".

    
por 10.04.2013 / 16:59
0

Eu fui na mesma rota pesquisando, experimentando o spooler de tarefas e assim por diante. O melhor dos melhores é este:

Paralelo GNU - semáforo - fg Também tem -j para trabalhos paralelos.

    
por 03.05.2016 / 12:12