Exécution de plusieurs commandes sur une seule ligne dans le shell

389

Dis que j'ai un fichier /templates/appleet que je veux

  1. le mettre à deux endroits différents et
  2. retirer l'original.

Donc, /templates/applesera copié sur /templates/usedET /templates/inuse puis après cela, je voudrais supprimer l'original.

La cpmeilleure façon de procéder est-elle suivie de rm? Ou existe-t-il une meilleure façon?

Je veux tout faire en une seule ligne, donc je pense que cela ressemblerait à quelque chose comme:

cp /templates/apple /templates/used | cp /templates/apple /templates/inuse | rm /templates/apple

Est-ce la bonne syntaxe?

John Redyns
la source

Réponses:

795

Vous utilisez |(pipe) pour diriger la sortie d'une commande vers une autre commande. Ce que vous recherchez, c'est un &&opérateur pour exécuter la commande suivante uniquement si la précédente a réussi:

cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apple

Ou

cp /templates/apple /templates/used && mv /templates/apple /templates/inuse

Pour résumer (de manière non exhaustive) les opérateurs / séparateurs de commandes de bash:

  • |redirige (pipelines) la sortie standard ( stdout) d'une commande vers l'entrée standard d'une autre. Notez que stderrva toujours dans sa destination par défaut, quelle qu'elle soit.
  • |&les deux stdoutet stderrune commande dans l’entrée standard d’une autre. Très utile, disponible en version bash 4 et supérieure.
  • &&n'exécute la commande de droite &&que si la précédente a réussi.
  • ||exécute la commande de droite ||uniquement si la précédente a échoué.
  • ;exécute la commande de droite de ;toujours, que la commande précédente ait réussi ou échoué. Sauf si a set -eété invoqué précédemment, ce qui provoque l' bashéchec d'une erreur.
Maxim Egorushkin
la source
6
A voté. Documentation officielle gnu.org/software/bash/manual/bash.html#Lists
flow2k
78

Pourquoi ne pas vous cprendre à l'emplacement 1, puis mvà l'emplacement 2. Cela permet de "retirer" l'original.

Et non, ce n'est pas la bonne syntaxe. |est utilisé pour "diriger" la sortie d'un programme et la transformer en entrée pour le programme suivant. Ce que vous voulez ;, c'est qui sépare plusieurs commandes.

cp file1 file2 ; cp file1 file3 ; rm file1

Si vous exigez que les commandes individuelles DOIVENT réussir avant que la suivante puisse être démarrée, alors vous utiliseriez à la &&place:

cp file1 file2 && cp file1 file3 && rm file1

De cette façon, si l'une des cpcommandes échoue, le rmne s'exécutera pas.

Marc B
la source
10

Notez que cp A B; rm Ac'est exactement mv A B. Ce sera aussi plus rapide, car vous n'avez pas besoin de copier les octets (en supposant que la destination se trouve sur le même système de fichiers), renommez simplement le fichier. Alors tu veuxcp A B; mv A C

glenn jackman
la source
7

Une autre option consiste à taper Ctrl+V Ctrl+Jà la fin de chaque commande.

Exemple (remplacer #par Ctrl+V Ctrl+J):

$ echo 1#
echo 2#
echo 3

Production:

1
2
3

Cela exécutera les commandes indépendamment de l'échec des précédentes.

Pareil que: echo 1; echo 2; echo 3

Si vous souhaitez arrêter l'exécution sur les commandes ayant échoué, ajoutez &&à la fin de chaque ligne, sauf la dernière.

Exemple (remplacer #par Ctrl+V Ctrl+J):

$ echo 1 &&#
failed-command &&#
echo 2

Production:

1
failed-command: command not found

Dans zshvous pouvez également utiliser Alt+Enterou Esc+Enterau lieu deCtrl+V Ctrl+J

Eyal Levin
la source
3

Essaye ça..

cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apple

Peter
la source
2

Utiliser des tuyaux me semble bizarre. Quoi qu'il en soit, vous devez utiliser l' andopérateur logique Bash:

$ cp /templates/apple /templates/used && cp /templates/apple /templates/inuse && rm /templates/apples

Si les cpcommandes échouent, le rmne sera pas exécuté.

Ou, vous pouvez créer une ligne de commande plus élaborée en utilisant une forboucle et cmp.

Renaud
la source