Comment puis-je exécuter plusieurs commandes qui ont & dans une ligne de commande?

12

J'ai rencontré un problème de maux de tête.

Je veux exécuter plusieurs commandes en arrière-plan, donc je veux les lancer en bash un par un. Il est facile de démarrer une commande dans le shell Linux en arrière-plan, comme ceci:

myCommand &

Il est également facile de démarrer plusieurs commandes, comme ceci:

myCommand1 && myCommand2

ou

myCommand1 ; myCommand2

Mais si je veux exécuter plusieurs commandes en arrière-plan, j'ai essayé le format de commande suivant, mais j'ai échoué:

myCommand1 & && myCommand2 &

ou

myCommand1 & ; myCommand2 &

Les deux formats échouent. Comment puis-je exécuter plusieurs commandes qui ont &dans une seule ligne de commande?

Horloge ZHONG
la source
2
Mettez-les dans un script et exécutez le script en arrière
Panther
Panther, il semble que l'utilisation de () pourrait aider à résoudre ce problème beaucoup plus facilement que l'utilisation d'un script. Essayons d'utiliser pleinement les fonctionnalités fournies par le shell lui-même, au lieu de composer ce que nous voulons par nous-mêmes. Mais bien sûr, l'utilisation d'un script pourrait également résoudre ce problème. Merci quand même.
Horloge ZHONG
Que faire si je veux exécuter un 'tail -F <file1>> <file2>' suivi de 'jobs -l', qui est à nouveau suivi de 'disown -h% 1'
akskap

Réponses:

24

Utilisation ().

Si vous souhaitez les exécuter séquentiellement:

(myCommand1; myCommand2) &

ou

(myCommand1 &) && (myCommand2 &)

Si vous souhaitez qu'ils fonctionnent en parallèle:

myCommand1 & myCommand2 &

En bash, vous pouvez également utiliser ceci (les espaces derrière les {et les; sont obligatoires):

{ myCommand1 && myCommand2; } &
Rinzwind
la source
3
(myCommand1 &) && (myCommand2 &)s'exécutera myCommand2même en cas d' myCommand1échec.
terdon
() pourrait aider bash à distinguer les & et &&. Il suffit donc d'utiliser () pour séparer l'unité d'exécution lorsque nous voulons utiliser les regroupements & et &&.
Horloge ZHONG du
16

Je suppose que tu veux ça:

myCommand1 & myCommand2 &

Cela démarre myCommand1et l'envoie à l'arrière-plan, suivi par l'esperluette, puis démarre immédiatement myCommand2et envoie également cela à l'arrière-plan, libérant ainsi à nouveau le shell.

Listes

Pour une meilleure compréhension, vous pouvez remplacer le pipeline par commande ici.

Une liste est une séquence d'un ou plusieurs pipelines séparés par l'un des opérateurs ; , & , && , ou || , et éventuellement terminé par l'un des ; , & , ou .

Si une commande est terminée par l'opérateur de contrôle & , le shell exécute la commande en arrière-plan dans un sous-shell. Le shell n'attend pas la fin de la commande et l'état de retour est 0. Commandes séparées par un ; sont exécutés séquentiellement; le shell attend que chaque commande se termine à son tour. L'état de retour est l'état de sortie de la dernière commande exécutée.

Les listes ET et OU sont des séquences d'un ou plusieurs pipelines séparés par les symboles && et || opérateurs de contrôle, respectivement.
La source:man bash

Décomposons cela en exemples. Vous pouvez créer une liste en combinant des commandes et en les séparant par l'une des suivantes ; & && ||:

command1 ; command2  # runs sequentially
command1 && command2 # runs sequentially, runs command2 only if command1 succeeds
command1 || command2 # runs sequentially, runs command2 only if command1 fails
command1 & command2  # runs simultaneously

Vous pouvez mettre fin à des listes avec l'une des options suivantes ; & <newline>:.
Normalement, vous exécutez une commande ou une liste en appuyant sur Enter, cela équivaut à <newline>. Le point-virgule ;remplit la même fonction, en particulier dans les scripts. Esperluette &démarre cependant la ou les commandes dans un sous-shell en arrière-plan, libérant immédiatement le shell.

Vous pouvez utiliser ()des crochets ronds ou bouclés {}pour créer d'autres listes de groupes, la différence étant que les crochets ronds génèrent un sous-shell et les bouclés non. Les accolades ont besoin d'un espace après le premier et d'un point-virgule ou d'un retour à la ligne avant le crochet de fermeture. Par exemple:

# if c1 succeeds start a shell in the background
# and run c2 and c3 sequentially inside it
c1 && ( c2 ; c3 ) & 
# run c1 and if it succeeds c2 sequentially as a group command
# if c1 or c2 fail run c3 in the background
{ c1 && c2 ;} || c3 &

Cela peut devenir assez compliqué, si vous n'êtes pas sûr de l'utilisation trueet falsepour tester si la construction fonctionne comme prévu:

$ { true && true ;} || echo 2
$ { true && false ;} || echo 2
2

Contrôle des travaux

La jobscommande affiche une liste des tâches d'arrière-plan en cours d'exécution ou récemment terminées dans le shell actuel. Il existe un certain nombre de raccourcis clavier et de commandes pour le contrôle des travaux:

  • Ctrl+ Zsaisit le caractère de suspension qui provoque l'arrêt du processus en cours d'exécution au premier plan, il n'est pas terminé, mais reste dans la jobsliste
  • Ctrl+ Ysaisit le caractère de suspension retardée qui provoque l'arrêt du processus en cours d'exécution au premier plan lorsqu'il tente de lire l'entrée du terminal
  • fg= %met un processus au premier plan en le démarrant si nécessaire, vous pouvez spécifier le processus comme suit:

     %       # last process in the jobs list
     %1      # 1st process in the jobs list
     %abc    # process beginning with the string “abc”
     %?abc   # process containing the string “abc” anywhere
  • bg= %&prend un processus en arrière-plan en le démarrant si nécessaire:

     %&      # last process in the jobs list
     %1&     # 1st process in the jobs list
     %abc&   # process beginning with the string “abc”
     %?abc&  # process containing the string “abc” anywhere
  • wait attend la fin d'un processus d'arrière-plan et renvoie son état de fin:

     wait %1 # 1st process in the jobs list

    Imaginez que vous avez commencé un long processus ( jobsrévèle qu'il est le numéro 3) et réalisez ensuite que vous voulez que l'ordinateur soit suspendu à la fin, plus echoun message si le processus n'a pas réussi:

     wait %3 || echo failed ; systemctl suspend
dessert
la source
Mais il est important d'être prudent avec && cela dépend de ce que la commande retourne , donc nous devons être sûrs que tout ce que nous appelons retourne réellement quelque chose bash considère une valeur véridique ..?
mathreadler
@mathreadler À moins que vous ne parliez d'un script utilisateur mal fait, la valeur de sortie est très bien définie (voir man bash) et largement utilisée exactement comme prévu AFAIK - Je n'ai jamais rien vécu de bizarre.
dessert
exactement, il faut faire attention aux scripts utilisateur mal faits. Ils existent et peuvent être pénibles à trouver de tels bugs. Askubuntu ne me permet pas de "@ dessert" vous.
mathreadler
Ah d'accord, cela a du sens maintenant que vous en parlez.
mathreadler