web-dev-qa-db-fra.com

Comment exécuter des commandes comme dans une file d'attente

Je dois beaucoup copier de divers fichiers dans divers dossiers. Je peux ajouter toutes mes commandes de copie à un script bash, puis l'exécuter, mais je dois attendre jusqu'à la fin si je souhaite ajouter d'autres commandes à cette "file" de copie.

Est-il possible d'exécuter des commandes en tant que file d'attente et d'ajouter d'autres commandes à cette file d'attente pendant que les choses fonctionnent?

Expliqué d'une manière différente, je veux démarrer une tâche longue. Pendant que cela fonctionne, je veux en lancer un autre qui ne démarre réellement que lorsque le premier est terminé. Et puis ajoutez un autre après ce dernier et ainsi de suite. Est-ce possible d'une certaine manière?

41
Svish

L'utilitaire at , mieux connu pour l'exécution de commandes à une heure spécifiée, possède également une fonction de file d'attente et peut être invité à démarrer l'exécution de commandes maintenant. Il lit la commande à exécuter à partir de l'entrée standard.

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

La commande batch équivaut à at -q b -m now (-m, ce qui signifie que le résultat de la commande, le cas échéant, vous sera envoyé, comme le fait cron). Toutes les variantes unix ne prennent pas en charge les noms de file d'attente (-q myqueue); vous pouvez être limité à une seule file appelée b. La variable at de Linux est limitée aux noms de file d'attente d'une seule lettre.

24
Gilles

Ajoutez & à la fin de votre commande pour l’envoyer en arrière-plan, puis wait avant de lancer la prochaine. Par exemple:

$ command1 &
$ wait; command2 &
$ wait; command3 &
$ ...
21
Vortico

Les solutions de Brad et Mankoff sont toutes deux de bonnes suggestions. Une autre combinaison semblable à une combinaison des deux consisterait à utiliser GNU Screen pour implémenter votre file d'attente. Cela présente l’avantage de pouvoir s’exécuter en arrière-plan. Vous pouvez le vérifier à tout moment et les mettre en file d’attente de nouvelles commandes ne fait que les coller dans le tampon à exécuter après la fermeture des commandes précédentes.

Première exécution:

$ screen -d -m -S queue

(accessoirement, le moment est venu de jouer avec des images géniales. des fichiers screenrc )

Cela créera une session d'écran en arrière-plan pour votre file d'attente nommée.

Maintenant, mettez en file d'attente autant de commandes que vous le souhaitez:

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

Je fais plusieurs commandes dans ce qui précède juste pour les tests. Votre cas d'utilisation ressemblerait probablement davantage à:

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

Notez que le "^ M" dans ma ligne ci-dessus est un moyen d’obtenir une nouvelle ligne incorporée qui sera interprétée plus tard après que l’écran l’a insérée dans votre shell bash existant. Utilisez "CTL-V" pour obtenir cette séquence.

Il serait assez facile de créer de simples scripts Shell pour automatiser cela et mettre les commandes en file d'attente. Ensuite, chaque fois que vous souhaitez vérifier l'état de votre file d'attente en arrière-plan, vous vous reconnectez via:

screen -S queue -r

Techniquement, vous n'avez même pas besoin de nommer votre session écran et cela fonctionnera bien, mais une fois que vous y êtes accroché, vous voudrez toujours en laisser une en cours d'exécution tout le temps. ;-)

Bien sûr, si vous faites cela, un autre bon moyen de le faire serait de nommer l’une des "files" de windows actuelles et d’utiliser:

screen -S queue -p queue -X stuff "command"
11
Jordan

Il existe un utilitaire que j'ai utilisé avec un grand succès pour le cas d'utilisation que vous décrivez. Récemment, j'ai déplacé mon ordinateur portable principal vers un nouveau matériel, ce qui impliquait le transfert de certains fichiers vers un NAS et le reste d'entre eux vers la nouvelle machine.

Voici comment je l'ai fait.

  1. Configurez toutes les machines impliquées avec une connexion réseau afin qu'elles puissent se joindre.

  2. Sur la machine à partir de laquelle vous déplacez des fichiers (ci-après appelée machine source), installez rsync avec apt-get install rsync et le secret-sauce Spooler de tâches (website http://vicerveza.homeunix.net/~viric/soft/ts/ ). Si vous êtes sur Debian, le nom du paquet pour ts est task-spooler et l'exécutable est renommé en tsp pour éviter les conflits de noms avec l'exécutable ts du paquetage moreutils. Le paquet Debian lié au site Web est parfaitement installable sur Ubuntu avec dpkg -i task-spooler_0.7.3-1_AMD64.deb ou similaire.

  3. Assurez-vous également que SSH est installé sur toutes les machines avec apt-get install openssh-server. Sur la machine source, vous devez configurer SSH pour permettre la connexion sans mot de passe aux machines cibles. La méthode la plus utilisée est l’authentification à clé publique avec ssh-agent (voir https://www.google.se/search?q=ssh+public+key+authentication pour exemples de cela), mais j’utilise parfois une méthode plus simple qui fonctionne tout aussi bien avec l’authentification par mot de passe. Ajoutez les éléments suivants à la configuration de votre client SSH (~/.ssh/config ou /etc/ssh/ssh_config):

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

    Ouvrez ensuite un terminal sur la machine source, connectez-vous avec ssh target1, authentifiez-vous comme d'habitude, puis laissez ce terminal ouvert. Notez qu'il existe un fichier de socket nommé ~/.ssh/master-user@target1:22. Il s'agit du fichier qui gardera une session maître authentifiée ouverte et autorisera les connexions sans mot de passe ultérieures pour user (tant que la connexion utilise les mêmes nom d'hôte et port cibles).

    À ce stade, vous devez vérifier que vous pouvez vous connecter sans être invité à vous authentifier auprès des ordinateurs cibles.

  4. Exécutez maintenant ts rsync -ave ssh bigfile user@target1: pour un seul fichier ou ts rsync -ave ssh bigdir user@target1: pour un répertoire. Avec rsync, il est important de ne pas inclure de barre oblique finale dans le répertoire (bigdir par rapport à bigdir/), sinon rsync supposera que vous entendiez l'équivalent de bigdir/* dans la plupart des autres outils.

    Le spouleur de tâches renverra l'invite et vous permettra de mettre en file d'attente plusieurs de ces commandes. Inspectez la file d'attente avec ts sans arguments.

Le spouleur de tâches présente de nombreuses fonctionnalités, telles que la réorganisation de la file d'attente, l'exécution d'un travail spécifique uniquement si un autre travail a été exécuté avec succès, etc. Consultez l'aide avec ts -h. J'inspecte parfois la sortie de la commande lorsqu'elle est exécutée avec ts -c.

Il existe d'autres méthodes pour ce faire, mais pour votre cas d'utilisation, elles incluent toutes le spouleur de tâches. J'ai choisi d'utiliser rsync sur SSH pour conserver les horodatages des fichiers, ce que la copie sur SMB n'aurait pas.

8
holmb

J'ai besoin de trucs comme ça assez souvent aussi. J'ai écrit un petit utilitaire appelé after qui exécute une commande chaque fois qu'un autre processus est terminé. Cela ressemble à ceci:

#!/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;

Vous le lancez alors comme ceci:

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

Le gros avantage de cette approche par rapport à d’autres approches est que le premier travail n’a pas besoin d’être exécuté de manière particulière, vous pouvez suivre n’importe quel processus avec votre nouvel emploi.

4
Ken Williams

Command1 && Command2

  • "&&" signifie que commande2 ne s'exécute qu'après que commande1 se termine avec un code retour égal à 0
  • Remarque: a || signifie que commande2 ne s'exécute qu'après son exécution par un code de retour autre que 0.
2
naftuli

Vous pouvez simplement ajouter des commandes à la ligne de commande de Shell qui exécute déjà une commande.

Tapez avec soin ou tapez-le ailleurs, vérifiez et copiez-collez. Même si la commande en cours crache des lignes de sortie, vous pouvez toujours taper quelque chose de nouveau, appuyer sur entrée et elle sera exécutée lorsque toutes les commandes seront exécutées ou entrées avant la fin.

L'exemple suit. Vous pouvez couper et coller le tout, ou entrer les commandes suivantes pendant que la 1re est en cours d'exécution (si vous tapez très vite), ou plus probablement pendant que la 2e est en cours d'exécution .:

echo "foo"
sleep 10; echo "bar"
sleep 3
echo "baz"
1
user31752

la façon la plus commode de penser est de maintenir "l'état" de la file d'attente avec de simples fichiers de verrouillage dans/tmp. Lorsque file1.sh exécute ses commandes cp, il conservera un fichier de verrouillage (ou lien dur) dans/tmp. quand c'est fait, effacez le fichier. Tous les autres scripts devront rechercher dans le fichier/tmp les fichiers verrouillés avec le schéma de nommage choisi. Naturellement, cela est sujet à toutes sortes d'échecs, mais son installation est triviale et tout à fait réalisable au sein de Bash.

0
Brad Clawsie