Existe-t-il une façon de mettre en queue des tâches de longue durée?

Existe-t-il une façon de faire ce qui suit dans un terminal unix:

  1. Démarrer un long process
  2. Ajouter un autre process de longue durée pour commencer lorsque le précédent est terminé
  3. Répétez l'étape 2 jusqu'à ce que j'ai mis en queue les process dont j'ai besoin d'être exécuté

La raison, je request, c'est que j'ai des choses longues que je dois faire. Je pourrais mettre toutes les commands dans un simple script bash et l'exécuter, mais le problème, c'est que je ne suis pas toujours sûr de ce que j'ai besoin d'exécuter. Donc, si je démarre le script, puis je me souviens d'un autre que je devais exécuter, je dois heurter plusieurs fois jusqu'à ce que tous les process soient tués, éditer le script et append mon nouveau process, puis recommencer le tout.

Ce que je fais actuellement en ce moment est de copyr beaucoup de files volumineux sur différents disques durs externes, et je ne sais pas exactement ceux que j'ai besoin de copyr et à l'endroit où j'aimerais commencer. Je sais que j'ai besoin de copyr, puis ajoute à la queue, car je comprends le rest.

J'espère que cela a du sens … Est-ce que tout cela est possible?

5 Solutions collect form web for “Existe-t-il une façon de mettre en queue des tâches de longue durée?”

La coquille est parfaite pour cela.

  1. Commencez le premier programme.
  2. Appuyez sur Ctrl-z pour suspendre le programme.
  3. Commencez le prochain programme.
  4. Répétez les étapes 2 et 3 pour append plus de programmes à la queue. Tous les programmes seront en mode Suspendu.
  5. Maintenant, exécutez la queue comme ceci:

     while fg; do :; done 

    Vous ne pouvez pas suspendre cette boucle while ou sortir bash jusqu'à ce que la queue soit terminée.

Si vous devez vous déconnecter (par exemple, les programmes fonctionneront pendant de nombreux jours), envisagez d'exécuter les étapes ci-dessus à l' screen .

Pas très élégant, mais rapide et sale:

 process1 & while kill -0 $! ; do sleep 1; done && process2 & while kill -0 $! ; do sleep 1; done && process3 & 

Vous devriez replace les PID réels pour $! si vous avez exécuté des travaux d'arrière-plan intermédiaires.

La réponse à votre question générale est: Absolument. Au début de l'informatique, le traitement par lots était le seul moyen de faire tout, et même lorsque des systèmes interactifs multi-users ont été inventés, la capacité de traitement par lot était la norme pour les gros travaux. Et il est encore courant aujourd'hui dans des environnements à moyen et à grande échelle utilisant des systèmes tels que Sun Grid Engine ou Torque .

Cependant, c'est probablement trop pour ce dont vous avez besoin. Vous pouvez configurer un système plus léger pour exécuter des scripts dans une queue série, mais je ne pense pas que cette approche soit particulièrement adaptée à votre tâche spécifique. Présumer des copys parallèles sur différents lecteurs sont acceptables, je pense que je l'attaquer comme ceci:

  1. Créez une structure de directory correspondant à vos unités cible:

    ~/copysystem/drive1/ ~/copysystem/drive2/ ~/copysystem/drive3/

  2. Installer Incron .

  3. Configurez une input incrontab pour chacun de ces directorys, qui exécute automatiquement votre script de copy sur IN_MOVED_TO.

  4. Faites de votre script soit a) tuez les instances antérieures du même script quand il démarre ou b) utilisez un file de locking basé sur mkdir et bloquez jusqu'à ce que le verrou soit effacé.

Ensuite, tout ce que vous devez faire est de déplacer des files sur les différents ~/copysystem/drive# , et ils sont tous copiés magiquement sur votre destination.

Surtout dans le cas de 4a, vous voulez probablement utiliser rsync -aP pour copyr vos files, afin que vous puissiez redémarrer des transferts partiels du milieu. (Possiblement en combinaison avec --remove-sent-files , si vous souhaitez vous débarrasser des originaux.)

Si vous souhaitez ignorer la complication de l'utilisation d'incron, vous pouvez encore profiter de la création de votre script sur un file de locking. Cela fonctionne comme ceci:

 #!/bin/bash LOCKDIR="/var/run/copysystem/copysystem.lock" while ! mkdir $LOCKDIR ; do echo "waiting for lock" sleep 5 done trap rmdir $LOCKDIR EXIT rsync commands go here.... 

Cela fonctionne parce que mkdir est une opération atomique – s'il réussit, vous savez que le directory n'existait pas. C'est important, car si vous utilisez quelque chose comme ça ! -f && touch ! -f && touch , il y a une condition de course. (Identique à la numérisation de la table des process pour les commands rsync ou similaires).

Si c'est quelque chose que vous allez faire régulièrement, il vaut la peine de configurer une sorte de planificateur pour le gérer pour vous.

J'aime l'élégance de la solution d'Aleksandr – et elle aborde tous les points que vous avez créés à l'origine – mais je vois que cela a des limites.

J'ai déjà utilisé le ldd de BSD comme une méthode de mise en queue des travaux: le «pilote d'imprimante» est juste un script shell, donc il est facile de s'adapter à différentes tâches (dans mon cas, cela signifiait la gestion de 4 modems pour l'interrogation des données, l'envoi de télécopys, SMS et d'autres choses).

Ce que vous voulez, c'est une queue de command non interactive. Bonnes nouvelles! J'en ai écrit un pour vous.

enqueue_cmd :

 #!/usr/bin/perl -w # Enqueue a job use ssortingct; use Fcntl qw(:flock); my $JOB_QUEUE_FILE = '/var/tmp/job_queue'; my $LOCK_TRIES = 5; my $LOCK_SLEEP = 1; my $jq; open $jq, ">> $JOB_QUEUE_FILE" or die "!open $JOB_QUEUE_FILE: $!"; my $locked = 0; LOCK_ATTEMPT: for (my $lock_sortinges = 0; $lock_sortinges < $LOCK_TRIES; $lock_sortinges++) { if (flock $jq, LOCK_EX) { $locked = 1; last LOCK_ATTEMPT; } sleep $LOCK_SLEEP; } $locked or die "could not lock $JOB_QUEUE_FILE"; for (@ARGV) { print $jq "$_\n"; } close $jq; 

dequeue_cmd :

 #!/usr/bin/perl -w # Dequeue a jobs and run them use ssortingct; use Fcntl qw(:seek :flock); use FileHandle; my $QUEUE_FILE = '/var/tmp/job_queue'; my $OUTPUT_FILE = '/var/tmp/job_out'; my $LOCK_TRIES = 5; my $LOCK_SLEEP = 1; my $JOB_SLEEP = 1; my $locked; my $jo; open $jo, ">> $OUTPUT_FILE" or die "!open $OUTPUT_FILE: $!"; $jo->autoflush(1); my $jq; open $jq, "+< $QUEUE_FILE" or die "!open $QUEUE_FILE: $!"; my @jobs = ( ); my $job; JOB: while (1) { if (-s $QUEUE_FILE == 0) { sleep $JOB_SLEEP; next JOB; } $locked = 0 LOCK_ATTEMPT: for (my $lock_sortinges = 0; $lock_sortinges < $LOCK_TRIES; $lock_sortinges++) { if (flock $jq, LOCK_EX) { $locked = 1; last LOCK_ATTEMPT; } sleep $LOCK_SLEEP; } $locked or die "could not lock $QUEUE_FILE"; seek $jq, 0, SEEK_SET or die "could not seek to start of file"; push @jobs, <$jq>; truncate $jq, 0 or die "could not truncate $QUEUE_FILE"; seek $jq, 0, SEEK_SET or die "could not seek to start of $QUEUE_FILE"; flock $jq, LOCK_UN; for $job (@jobs) { chomp $job; print $jo "## executing $job\n"; print $jo `$job`; } sleep $JOB_SLEEP; } 

D'abord, exécutez nohup ./dequeue_cmd & , puis ajoutez vos commands comme nohup ./dequeue_cmd & :

 ./enqueue_cmd "echo 'hello world'" "sleep 5" "date" ./enqueue_cmd "ls /var/tmp" 

La sortie apparaît dans /var/tmp/job_out :

 tail -F /var/tmp/job_out ## executing echo 'hello world' hello world ## executing sleep 5 ## executing date Fri Dec 10 16:35:43 PST 2010 ## executing ls /var/tmp ff job_out job_queue ss 
Les astuces du serveur de linux et windows, tels que ubuntu, centos, apache, nginx, debian et des sujets de réseau.