Como executar comandos como em uma fila

37

Eu preciso copiar bastante arquivos para várias pastas. Posso adicionar todos os meus comandos de cópia a um script bash e depois executá-lo, mas depois preciso aguardar até que seja concluído se quiser adicionar mais comandos a essa "fila" de cópia.

Existe uma maneira de executar comandos como uma fila e adicionar mais comandos a essa fila enquanto as coisas estão em execução?

Explicado de uma maneira diferente, quero começar uma tarefa longa. Enquanto isso estiver em execução, quero iniciar outro que realmente não inicia até que o primeiro seja concluído. E então adicione outro depois daquele último e assim por diante. Isso é possível de alguma forma?

    
por Svish 10.12.2010 / 00:08

8 respostas

23

O utilitário at , mais conhecido por executar comandos em um horário especificado, também tem um recurso de fila e pode ser solicitado a iniciar a execução de comandos agora. Ele lê o comando para executar a partir da entrada padrão.

echo 'command1 --option arg1 arg2' | at -q myqueue now
echo 'command2 ...' | at -q myqueue now

O comando batch é equivalente a at -q b -m now ( -m significando o saída de comando, se houver, será enviada para você, como o cron faz). Nem todas as variantes unix suportam nomes de fila ( -q myqueue ); você pode estar limitado a uma única fila chamada b . O at do Linux está limitado a nomes de fila de uma única letra.

    
por 11.12.2010 / 00:28
20

Anexe o & ao final do seu comando para enviá-lo para o segundo plano e, em seguida, wait antes de executar o próximo. Por exemplo:

$ command1 &
$ wait; command2 &
$ wait; command3 &
$ ...
    
por 17.08.2012 / 04:26
11

As soluções de Brad e Mankoff são boas sugestões. Outra que é semelhante a uma combinação de ambos seria usar GNU Screen para implementar sua fila. Isto tem a vantagem de poder rodar em segundo plano, você pode verificá-lo sempre, e colocar novos comandos em fila apenas os cola no buffer para ser executado após os comandos anteriores saírem.

Primeiro, execute:

$ screen -d -m -S queue

(aliás, agora é um bom momento para jogar com alguns arquivos screenrc )

impressionantes.

Isso gerará uma sessão de tela em segundo plano para você chamada fila.

Agora, enfileire quantos comandos quiser:

screen -S queue -X stuff "echo first; sleep 4; echo second^M"

Estou fazendo vários comandos acima apenas para testes. Seu caso de uso provavelmente seria mais parecido com:

screen -S queue -X stuff "echo first^M"
screen -S queue -X stuff "echo second^M"

Note que o "^ M" na minha linha acima é uma maneira de obter uma nova linha incorporada que será interpretada mais tarde, depois que a tela for inserida em seu shell bash existente. Use "CTL-V" para obter essa sequência.

Seria muito fácil criar alguns scripts de shell simples para automatizar isso e colocar em fila os comandos. Então, sempre que você quiser verificar o status de sua fila em segundo plano, anexe novamente via:

screen -S queue -r
Tecnicamente, você nem precisa nomear sua sessão de tela e ela funcionará bem, mas uma vez que você ficar viciado, você vai querer deixar uma rodando o tempo todo de qualquer maneira. ;-)

Claro, se você fizer isso, outra boa maneira de fazer isso seria nomear uma das janelas atuais "queue" e usar:

screen -S queue -p queue -X stuff "command"
    
por 14.12.2010 / 05:31
7

Existe um utilitário que usei com grande sucesso exatamente para o caso de uso que você está descrevendo. Recentemente, mudei meu laptop principal para um novo hardware, o que envolveu a transferência de alguns arquivos para um NAS e o restante para a nova máquina.

Foi assim que eu fiz.

  1. Configure todas as máquinas envolvidas com uma conexão de rede para que elas possam se comunicar.

  2. Na máquina de onde você está movendo arquivos (daqui em diante chamada de máquina de origem), instale o rsync com apt-get install rsync e o segredo-molho Task Spooler (site link ). Se você está no Debian o nome do pacote para ts é task-spooler e o executável é renomeado para tsp para evitar conflito de nome com o executável ts do pacote moreutils . O pacote Debian vinculado a partir do site é perfeitamente instalável no Ubuntu com dpkg -i task-spooler_0.7.3-1_amd64.deb ou similar.

  3. Verifique também se todas as máquinas possuem SSH instalado com apt-get install openssh-server . Na máquina de origem, você precisa configurar o SSH para permitir login sem senha nas máquinas de destino. O método mais usado é a autenticação de chave pública com ssh-agent (consulte link para exemplos disso), mas às vezes eu uso um método mais fácil que funciona tão bem quanto a autenticação de senhas. Adicione o seguinte à sua configuração de cliente SSH ( ~/.ssh/config ou /etc/ssh/ssh_config ):

    Host *
         ControlMaster auto
         ControlPath ~/.ssh/master-%r@%h:%p
    

    Em seguida, abra um terminal na máquina de origem, faça o login com ssh target1 , autentique como de costume e, em seguida, deixe este terminal aberto. Observe que há um arquivo de soquete denominado ~/.ssh/master-user@target1:22 , esse é o arquivo que manterá uma sessão mestre autenticada aberta e permitirá conexões subsequentes sem senha para user (desde que a conexão use o mesmo nome de host e porta de destino).

    Neste ponto, você precisa verificar se pode fazer o login sem receber uma solicitação de autenticação para as máquinas de destino.

  4. Agora, execute ts rsync -ave ssh bigfile user@target1: para um único arquivo ou ts rsync -ave ssh bigdir user@target1: para um diretório. Com o rsync, é importante não incluir uma barra no diretório ( bigdir comparado a bigdir/ ) ou o rsync assumirá que você significou o equivalente a bigdir/* na maioria das outras ferramentas.

    O Spooler de Tarefa retornará o prompt e permitirá que você enfileire muitos desses comandos sucessivamente. Inspecione a fila de execução com ts sem argumentos.

O Spooler de Tarefa possui muitos recursos, como reorganizar a fila de execução, executar uma tarefa específica somente se outra tarefa foi executada com êxito, etc. Visualizar a ajuda com ts -h . Às vezes, inspeciono a saída do comando enquanto ela está em execução com ts -c .

Existem outros métodos para fazer isso, mas, para o seu caso de uso, todos incluem o Spooler de Tarefa. Eu escolhi usar o rsync via SSH para preservar os timestamps de arquivos, que a cópia sobre o SMB não teria.

    
por 20.02.2013 / 10:58
4

Também preciso de coisas assim com bastante frequência. Eu escrevi um pequeno utilitário chamado after que executa um comando sempre que algum outro processo é concluído. Parece assim:

#!/usr/bin/perl

my $pid = shift;
die "Usage: $0 <pid> <command...>" unless $pid =~ /^\d+$/ && @ARGV;

print STDERR "Queueing process $$ after process $pid\n";
sleep 1 while -e "/proc/$pid";
exec @ARGV;

Você então o executa assim:

% command1 arg1 arg2 ...  # creates pid=2853
% after 2853 command2 arg1 arg2 ... # creates pid=9564
% after 9564 command3 arg1 arg2 ...

A grande vantagem disso em algumas outras abordagens é que o primeiro trabalho não precisa ser executado de maneira especial, você pode acompanhar qualquer processo com seu novo trabalho.

    
por 15.12.2012 / 00:22
1

Você pode simplesmente adicionar comandos à linha de comando do shell que já está executando um comando.

Digite com cuidado ou digite-o em outro lugar, verifique e recorte e cole. Mesmo que o comando atual esteja lançando linhas de saída, você ainda pode digitar algo novo, pressionar enter e ele será executado quando todos os comandos em execução ou inseridos antes de serem concluídos.

Exemplo a seguir. Você pode recortar e colar a coisa toda ou digitar os comandos subsequentes enquanto o primeiro está em execução (se você digitar muito rápido) ou, mais provavelmente, enquanto o segundo estiver em execução.:

echo "foo"
sleep 10; echo "bar"
sleep 3
echo "baz"
    
por 10.12.2010 / 00:48
1

Command1 & & Command2

  • o "& &" significa que o comando2 só é executado após o comando1 terminar com um código de retorno de 0
  • Nota: um || significa que o comando2 só é executado após o comando1 terminar com um código de retorno Diferente de 0
por 26.06.2014 / 12:40
0

A maneira mais hacky que eu posso imaginar é manter o "estado" da fila com arquivos de bloqueio simples em / tmp. quando o arquivo1.sh estiver executando seus comandos cp, ele manterá um arquivo de bloqueio (ou hardlink) em / tmp. quando terminar, apague o arquivo. todos os outros scripts terão que procurar em / tmp os arquivos de bloqueio com o esquema de nomeação escolhido. naturalmente, isso está sujeito a todos os tipos de falhas, mas é trivial configurar e é totalmente possível dentro do bash.

    
por 10.12.2010 / 00:45