39 votes

Pourquoi combiner des commandes sur une seule ligne dans un script Bash ?

Je suis novice en matière de Linux et de script Bash. Au travail, j'ai vu des scripts avec des constructions similaires à celle-ci :

mkdir build && cd build && touch blank.txt

Ou bien :

mkdir build; cd build; touch blank.txt

Ou même l'exotique :

COMMAND="mkdir build && cd build && touch blank.txt"
eval ${COMMAND}

Le dernier exemple donne un cas d'utilisation possible où une seule ligne pourrait être utile, mais généralement ce qui suit est plus facile à lire et (au moins pour moi) vous permet de déboguer visuellement le script :

mkdir build
cd build
touch blank.txt

Y a-t-il des avantages techniques à tout mettre sur une seule ligne ?

59voto

pa4080 Points 27038
mkdir build && cd build && touch blank.txt

En Bash (et dans d'autres shells et dans la plupart des langages de programmation de haut niveau) && est une logique y ce qui signifie que si la commande précédente renvoie un résultat positif, la commande suivante sera exécutée. Il existe également des commandes logiques ou || . Par exemple, vous pouvez combiner ces deux options en une seule déclaration :

mkdir /tmp/abc/123 && echo 'the dir is created' || echo "the dir isn't created"

Remarque : la construction cmd_1 && cmd_2 || comd_3 n'est pas un substitut de la if.. then.. else car quelle que soit la commande précédente qui renvoie une valeur fausse, l'instruction cmd_3 sera exécutée. Vous devez donc faire attention aux circonstances dans lesquelles vous l'utilisez. Voici un exemple :

$ true && false || echo success
success
$ false && true || echo success
success
$ false && false || echo success
success

En règle générale, lorsque j'utilise l'option cd dans un script, je mets un test pour savoir si le changement de répertoire est réussi : cd somewhere/ || exit . Le test le plus approprié est proposé par @dessert : if ! cd dir; then exit 1; fi . Mais dans tous les cas, pour se prémunir contre l'échec de script, il est préférable d'utiliser l'option set -e telle qu'elle est présentée dans le Réponse de @mrks .


mkdir build; cd build; touch blank.txt

; est un délimiteur de ligne et est utilisé lorsque plusieurs commandes séparées sont écrites sur une même ligne.


Noter quand ; ou && et || sont utilisées, il n'est pas obligatoire d'écrire les commandes à la ligne - ceci est illustré dans la section Réponse de @allo .

En tout état de cause, il n'y a pas d'avantage ou de différence technique particulière entre le fait d'écrire les commandes sur une seule ligne ou sur des lignes séparées.


COMMAND="mkdir build && cd build && touch blank.txt"
eval ${COMMAND}

Ici, une ou plusieurs commandes (et leurs arguments) sont regroupées en tant que valeur d'une variable, puis cette variable (argument) est convertie en commande à l'aide de la fonction eval . Vous pourrez ainsi modifier la commande qui sera exécutée plusieurs fois dans un script en la modifiant à un seul endroit.

Supposons que vous souhaitiez modifier la façon dont le fichier blank.txt est créé, par exemple, vous pouvez modifier la ligne concernée de la manière suivante :

COMMAND="mkdir build && cd build && echo 'test' > blank.txt"

Les données réelles eval 's avantage sur l'utilisation de alias c'est lorsqu'il y a re-directions, tuyaux, opérateurs logiques - à tous les opérateurs de flux de contrôle - en cours d'utilisation.

Dans la plupart des cas, vous pouvez utiliser functions au lieu de eval quand alias n'est pas applicable. De même, si la variable ne contient qu'une seule commande, c'est-à-dire CMD="cat" Nous n'avons pas besoin de eval parce que le découpage en mots de Bash élargira le champ d'application de la loi. "$CMD" "$file1" "$file2" correctement.

13voto

Greg Annandale Points 101

Les réponses données jusqu'à présent portent sur ce qui se passe/comment cela fonctionne, mais je pense que vous demandiez "pourquoi"

La principale "raison" de le faire (pour moi) plutôt que de les taper sur trois lignes est que parfois les commandes prennent du temps (parfois des minutes) et que vous ne voulez pas attendre pendant tout ce temps.

Par exemple, je pourrais construire && déployer && Je démarre mon application, puis je sors déjeuner. Le processus peut durer 15 minutes. Cependant, comme j'ai utilisé && il ne sera pas déployé si la construction échoue, donc cela fonctionne.

Type-ahead est une alternative mais elle est incertaine, vous pourriez ne pas être capable de voir ce que vous tapez (et donc faire des erreurs) ou un programme pourrait manger le type-ahead (Merci, grails !). En rentrant du déjeuner, vous vous apercevez qu'il vous reste deux tâches assez longues à lancer à cause d'une faute de frappe.

L'autre solution consiste à écrire un petit script ou un alias. Ce n'est pas une mauvaise idée mais cela ne permet pas autant de flexibilité que moi :

stop && build && test && deploy && start 

ou je peux juste :

stop && start

Ou toute autre combinaison qui polluerait rapidement un script avec des tas de drapeaux.

Même si vous écrivez un script, vous êtes susceptible de l'intégrer à d'autres script à l'aide de && .

10voto

pymym213 Points 511

La combinaison de commandes sous Linux peut s'avérer très utile.

Un bon exemple peut être le redémarrage d'une interface réseau distante via ssh (si vous avez changé la configuration du réseau ou autre...).

ifdown eth0 && ifup eth0

Cela peut vous empêcher de vous rendre physiquement sur le serveur afin de faire apparaître l'interface sur laquelle vous vous êtes initialement connecté en mode ssh. (Vous ne pourrez pas exécuter ifup eth0 もし ifdown eth0 est exécuté seul).

7voto

Sergiy Kolodyazhnyy Points 97292

Que font les commandes ?

Pour comprendre le pourquoi, il faut aussi comprendre ce qui est fait. Les scripts sont séquentiels. Dans votre dernier exemple :

mkdir build
cd build
touch blank.txt

cd build sera exécutée indépendamment de mkdir build réussir ou non. Bien entendu, si mkdir fails Vous verrez apparaître l'erreur suivante cd .

mkdir build; cd build; touch blank.txt est un liste séquentielle . On peut considérer que c'est essentiellement la même chose que plusieurs lignes script. La grammaire script traitera cela légèrement différemment, mais le résultat sera exactement le même que ci-dessus. Là encore, les commandes sont exécutées indépendamment de la réussite ou non de la précédente.

Enfin, il y a

mkdir build && cd build && touch blank.txt

qui est un Listes ET - une séquence d'une ou plusieurs conduites (ou commandes) séparées par des && de l'opérateur. Les commandes de cette liste sont exécutées avec une associativité de gauche. Cela signifie que le Shell continuera à prendre deux commandes/pipelines séparées par des && exécuter d'abord celui de gauche, puis celui de droite seulement si celui de gauche a réussi (a renvoyé un état de sortie nul).

Dans cet exemple, que se passera-t-il ?

  • Shell exécute mkdir build d'abord.
  • la commande ci-dessus a réussi (code de sortie 0), cd build fonctionnera
  • Examinons à nouveau l'associativité gauche. ... && touch blank.txt . A fait des choses à gauche de && réussir ? Si oui, lancez touch blank.txt .

Pourquoi utiliser des listes séquentielles plutôt qu'une liste AND ?

La liste séquentielle mkdir build; cd build; touch blank.txt a du sens lorsque l'on accepte que l'une des commandes échoue. Supposons que mkdir build existe déjà. Nous voulons toujours cd dans le build/ et touch blank.txt . Bien sûr, l'inconvénient est qu'il y a une possibilité de résultat involontaire. Que se passerait-il si build n'a pas de bit d'exécution défini, et c'est pourquoi cd build échoue ? Le touch blank.txt se produira dans notre répertoire de travail actuel au lieu du répertoire de travail prévu build/ .

Considérons maintenant mkdir build && cd build && touch blank.txt . Cette solution est un peu plus logique, mais elle comporte ses propres pièges. Si build existe déjà, il est probable que quelqu'un ait déjà fait le touch blank.txt également, de sorte que nous pourrions ne pas vouloir faire de touch blank.txt car cela modifiera l'horodatage de l'accès, ce qui n'est pas forcément souhaitable.

Conclusion

Le fait de placer les commandes sur la même ligne dépend de l'objectif des commandes et de ce que vous essayez de réaliser. Les listes séquentielles peuvent simplifier la sortie, car Shell ne réaffiche pas l'invite tant que les commandes ne sont pas terminées. La liste AND permet l'exécution conditionnelle des commandes et peut empêcher l'exécution de commandes inutiles. En définitive, l'utilisateur doit connaître les différences et savoir quel outil choisir en fonction de la tâche à accomplir.

5voto

WinEunuuchs2Unix Points 91128

Pourquoi nous aimons parfois l'utiliser

Lorsque nous rédigeons des réponses ici en Demander à Ubuntu il est utile de les regrouper sur une seule ligne, ce qui permet aux utilisateurs de les copier et de les coller plus facilement dans leur terminal. Par exemple :

$ CurrDir=$PWD ; cd /bin ; ls -la dd ; cd "$CurrDir"

-rwxr-xr-x 1 root root 72632 Mar  2  2017 dd

Comme indiqué précédemment, vous pouvez utiliser && pour le même effet, mais s'il y a des erreurs ci-dessus, vous pourriez vous retrouver dans le mauvais répertoire. Dans ce cas ; est préférable à && qui n'est pas testé pour le succès :

rick@alien:~/askubuntu$ CurrDir=$PWD && cd /bin && llllssss -la dd && cd "$CurrDir"

llllssss: command not found

rick@alien:/bin$ 

Pourquoi devons-nous l'utiliser ?

Pour certaines commandes, vous devez enchaîner plusieurs lignes. C'est le cas de la commande abrégée if -commandes- fi qui doit être d'une seule ligne. Par exemple :

$ [[ 2 -eq 2 ]] && { echo 2 equals 2 ; echo setting three to 3 ; three=3 ; }

2 equals 2
setting three to 3

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X