bash: lancer plusieurs commandes enchaînées en arrière-plan
j'essaie de lancer des commandes dans paralel, en arrière-plan, en utilisant bash. Voici ce que j'essaie de faire:
forloop {
//this part is actually written in perl
//call command sequence
print `touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;`;
}
"151910920 ` la partie entre backticks (" ) génère un nouveau shell et exécute les commandes successivement. Le fait est que le contrôle du programme original ne retourne que lorsque la dernière commande a été exécutée. Je voudrais exécuter l'instruction entière en arrière-plan (Je ne m'attends pas à des valeurs de sortie/retour) et je voudrais que la boucle continue exécuter.
le programme appelant (celui qui a la boucle) ne s'arrêterait pas tant que tous les shells générés ne seraient pas terminés.
je pourrais utiliser des threads en perl pour générer des threads différents qui appellent des coquillages différents, mais cela semble exagéré...
puis-je démarrer un shell, lui donner un ensemble de commandes et lui dire d'aller à l'arrière-plan?
14 réponses
je n'ai pas testé mais si 151920920"
print `(touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;) &`;
les parenthèses signifient exécuter dans une cellule mais cela ne devrait pas faire de mal.
Merci Hugh, qui l'a fait:
adrianp@frost:~$ (echo "started"; sleep 15; echo "stopped")
started
stopped
adrianp@frost:~$ (echo "started"; sleep 15; echo "stopped") &
started
[1] 7101
adrianp@frost:~$ stopped
[1]+ Done ( echo "started"; sleep 15; echo "stopped" )
adrianp@frost:~$
les autres idées ne fonctionnent pas parce qu'elles démarrent chaque commande en arrière-plan, et pas la séquence de commande (ce qui est important dans mon cas!).
Merci encore!
une Autre façon est d'utiliser la syntaxe:
{ command1; command2; command3; } &
wait
il n'y a pas de commande & après mais une à la fin du groupe cmd. Le wait
à la fin garantit que l'enfant engendré aura un parent jusqu'à ce qu'il se termine.
vous pouvez également faire des choses de fantaisie comme la redirection stderr
et stdout
:
{ command1; command2; command3; } 2>&2 1>&1 &
votre exemple ressemblerait à:
forloop() {
{ touch .file1.lock; cp bigfile1 /destination; rm .file1.lock; } &
}
# ... do some other concurrent stuff
wait # wait for childs to end
for command in $commands
do
"$command" &
done
wait
L'esperluette à la fin de la commande s'exécute en arrière-plan, et le wait
attend jusqu'à ce que la tâche d'arrière-plan est terminé.
GavinCattell a obtenu le plus proche (pour bash, IMO), mais comme Mad_Ady a souligné, il ne serait pas gérer les fichiers "lock". Cela devrait:
S'il y a d'autres jobs en attente, le wait attendra ceux-là aussi. Si vous devez attendre seulement les copies, Vous pouvez accumuler ces PID et attendre seulement ceux. Si pas, vous pouvez supprimer les 3 lignes avec "pid", mais c'est plus général.
en plus, j'ai ajouté la vérification pour éviter la copie tout à fait:
pids=
for file in bigfile*
do
# Skip if file is not newer...
targ=/destination/$(basename "${file}")
[ "$targ" -nt "$file" ] && continue
# Use a lock file: ".fileN.lock" for each "bigfileN"
lock=".${file##*/big}.lock"
( touch $lock; cp "$file" "$targ"; rm $lock ) &
pids="$pids $!"
done
wait $pids
incidemment, il semble que vous copiez de nouveaux fichiers vers un dépôt FTP (ou similaire). Si c'est le cas, vous pourrait envisager une stratégie de copie/renommer au lieu des fichiers de verrouillage (mais c'est un autre sujet).
L'installation de bash que vous cherchez s'appelle Compound Commands
. Voir la page de manuel pour plus d'informations:
Commandes Composées Une commande composée est l'une des suivantes:
(list) list is executed in a subshell environment (see COMMAND EXECUTION ENVIRONMENT below). Variable assignments and builtin commands that affect the shell's environment do not remain in effect after the command completes. The return status is the exit status of list. { list; } list is simply executed in the current shell environment. list must be terminated with a newline or semicolon. This is known as a group command. The return status is the exit status of list. Note that unlike the metacharac‐ ters ( and ), { and } are reserved words and must occur where a reserved word is permitted to be recognized. Since they do not cause a word break, they must be separated from list by whitespace or another shell metacharac‐ ter.
il y en a d'autres, mais ce sont probablement les 2 types les plus communs. La première, parens, se déroulera une liste de commande en série dans un shell interne est exécuté, tandis que le second, les accolades, une liste de commandes en série dans la coquille actuelle.
parens
% ( date; sleep 5; date; )
Sat Jan 26 06:52:46 EST 2013
Sat Jan 26 06:52:51 EST 2013
broches bouclées
% { date; sleep 5; date; }
Sat Jan 26 06:52:13 EST 2013
Sat Jan 26 06:52:18 EST 2013
exécuter la commande en utilisant un at job:
# date
# jue sep 13 12:43:21 CEST 2012
# at 12:45
warning: commands will be executed using /bin/sh
at> command1
at> command2
at> ...
at> CTRL-d
at> <EOT>
job 20 at Thu Sep 13 12:45:00 2012
le résultat sera envoyé à votre compte par courrier.
je suis tombé sur ce fil ici et a décidé de mettre en place un code snippet pour engendrer des déclarations enchaînées comme des travaux de fond. J'ai testé cela sur BASH pour Linux, KSH pour IBM AIX et Ash de Busybox pour Android, donc je pense qu'il est sûr de dire que cela fonctionne sur n'importe quel shell Bourne-like.
processes=0;
for X in `seq 0 10`; do
let processes+=1;
{ { echo Job $processes; sleep 3; echo End of job $processes; } & };
if [[ $processes -eq 5 ]]; then
wait;
processes=0;
fi;
done;
ce code exécute un certain nombre d'emplois d'arrière-plan jusqu'à une certaine limite d'emplois concurrents. Vous pouvez l'utiliser, par exemple, pour recompresser beaucoup de gzippé les fichiers avec xz
sans avoir un énorme tas de processus xz
dévorent toute votre mémoire et font vomir votre ordinateur: dans ce cas, vous utilisez *
comme la liste for
et le travail par lots serait gzip -cd "$X" | xz -9c > "${X%.gz}.xz"
.
essayez de mettre des commandes dans des accolades bouclées avec &s, comme ceci:
{command1 & ; command2 & ; command3 & ; }
ceci ne crée pas de sous-shell, mais exécute le groupe de commandes en arrière-plan.
HTH
Je ne sais pas pourquoi personne n'a répondu avec la bonne solution:
my @children;
for (...) {
...
my $child = fork;
exec "touch .file1.lock; cp bigfile1 /destination; rm .file1.lock;" if $child == 0;
push @children, $child;
}
# and if you want to wait for them to finish,
waitpid($_) for @children;
cela provoque Perl à engendrer des enfants pour exécuter chaque commande, et vous permet d'attendre que tous les enfants à compléter avant de procéder.
soit dit en passant,
print `some command`
et
system "some command"
sortie le même contenu à stdout, mais le premier a un plafond plus élevé, Perl doit capturer tout de " some command
" 's sortie
fourche dans une boucle pour:
for i in x; do ((a; b; c;)&); done
exemple:
for i in 500 300 100; do ((printf "Start $i: "; date; dd if=/dev/zero of=testfile_$i bs=1m count=$i 2>/dev/null; printf "End $i: "; date;)&) && sleep 1; done
exécuter les commandes dans une sous-station:
(command1 ; command2 ; command3) &
juste au cas où quelqu'un est toujours intéressé, vous pouvez le faire sans appeler un subshell comme ceci:
print `touch .file1.lock && cp bigfile1 /destination && rm .file1.lock &`;
vous pouvez utiliser la commande GNU parallel
pour exécuter des tâches en parallèle. Il est plus sûr sont plus rapides.
à mon avis, vous essayez de copier plusieurs gros fichiers de la source à la destination. Et pour cela, vous pouvez le faire en parallèle avec la déclaration ci-dessous.
$ ls *|parallel -kj0 --eta 'cp {} /tmp/destination'
comme nous avons utilisé l'option -j0
, tous les fichiers seront copiés en parallèle. Dans le cas où vous avez besoin de réduire le nombre de processus parallèles, alors vous pouvez utiliser -j<n>
où <n>
est le nombre de processus parallèles à exécuter.
Parallel recueillera également le résultat du processus et le signalera de manière séquentielle (avec l'option -k
), ce que les autres mécanismes de contrôle des tâches ne peuvent pas faire.
--eta
option vous donnera des statistiques détaillées du processus en cours. Nous pouvons donc savoir comment le processus a été achevé en mai et combien de temps cela prendra pour l'être.