Je vois souvent des tutoriels en ligne qui connectent diverses commandes avec différents symboles. Par exemple:
command1 | command2
command1 & command2
command1 || command2
command1 && command2
D'autres semblent connecter des commandes à des fichiers:
command1 > file1
command1 >> file1
Quelles sont ces choses? Comment s'appellent-ils? Que font-ils? Y en a-t-il plus?
On les appelle les opérateurs Shell et oui, il y en a plus. Je vais donner un bref aperçu des plus courants parmi les deux classes principales, opérateurs de contrôle et opérateurs de redirection , et comment ils fonctionnent par rapport au shell bash.
Dans le langage de commande Shell, un jeton qui exécute une fonction de contrôle.
Il s'agit de l'un des symboles suivants:& && ( ) ; ;; <newline> | ||
Et |&
En bash.
Un !
N'est pas pas un opérateur de contrôle mais un mot réservé . Il devient un NOT [opérateur de négation] logique à l'intérieur Expressions arithmétiques et à l'intérieur des constructions de test (tout en nécessitant toujours un délimiteur d'espace).
;
: Exécutera une commande après la fin d'une autre, quel que soit le résultat de la première.
command1 ; command2
command1
Est d'abord exécuté, au premier plan, et une fois terminé, command2
Sera exécuté.
Une nouvelle ligne qui n'est pas dans un littéral de chaîne ou après certains mots clés est pas équivalent à l'opérateur point-virgule. Une liste de commandes simples délimitées par ;
Est toujours une liste - comme dans l'analyseur Shell doit continuer à lire les commandes simples qui suivent une délimitation ;
une simple commande avant de l'exécuter, tandis qu'une nouvelle ligne peut délimiter une liste de commandes entière - ou une liste de listes. La différence est subtile, mais compliquée: étant donné que le shell n'a aucun impératif préalable pour lire les données après une nouvelle ligne, la nouvelle ligne marque un point où le shell peut commencer à évaluer les commandes simples qu'il a déjà lues, tandis qu'un ;
le point-virgule ne fonctionne pas.
&
: Cela exécutera une commande en arrière-plan, vous permettant de continuer à travailler dans le même shell.
command1 & command2
Ici, command1
Est lancé en arrière-plan et command2
Démarre immédiatement au premier plan, sans attendre que command1
Se termine.
Une nouvelle ligne après command1
Est facultative.
&&
: Utilisé pour construire des listes ET, il vous permet d'exécuter une commande uniquement si une autre s'est terminée avec succès.
command1 && command2
Ici, command2
S'exécutera après la fin de command1
Et seulement si command1
A réussi (si son code de sortie était 0). Les deux commandes sont exécutées au premier plan.
Cette commande peut également être écrite
if command1
then command2
else false
fi
ou simplement if command1; then command2; fi
si le statut de retour est ignoré.
||
: Utilisé pour créer des listes OR, il vous permet d'exécuter une commande uniquement si une autre s'est terminée sans succès.
command1 || command2
Ici, command2
Ne s'exécutera que si command1
A échoué (s'il a renvoyé un état de sortie autre que 0). Les deux commandes sont exécutées au premier plan.
Cette commande peut également être écrite
if command1
then true
else command2
fi
ou d'une manière plus courte if ! command1; then command2; fi
.
Notez que &&
Et ||
Sont associatifs à gauche; voir Priorité des opérateurs logiques Shell &&, pour plus d'informations.
!
: Ceci est un mot réservé qui agit comme l'opérateur "non" (mais doit avoir un délimiteur), utilisé pour annuler le statut de retour d'une commande - retourne 0 si la commande retourne un statut différent de zéro, retourne 1 s'il renvoie l'état 0. Également un NOT logique pour l'utilitaire test
.
! command1
[ ! a = a ]
Et un véritable opérateur NOT à l'intérieur des expressions arithmétiques:
$ echo $((!0)) $((!23))
1 0
|
: L'opérateur de pipe, il passe la sortie d'une commande en entrée à une autre. Une commande construite à partir de l'opérateur de tuyau est appelée pipeline .
command1 | command2
Toute sortie imprimée par command1
Est transmise en entrée à command2
.
|&
: Ceci est un raccourci pour 2>&1 |
En bash et zsh. Il transmet à la fois la sortie standard et l'erreur standard d'une commande en entrée à une autre.
command1 |& command2
;;
Est utilisé uniquement pour marquer la fin d'un instruction case . Ksh, bash et zsh prennent également en charge ;&
Pour passer au cas suivant et ;;&
(Pas dans ATT ksh) pour continuer et tester les cas suivants.
(
Et )
Sont utilisés pour commandes de groupe et les lancer dans un sous-shell. {
Et }
Regroupent également des commandes, mais ne les lancez pas en sous-shell. Voir cette réponse pour une discussion sur les différents types de parenthèses, crochets et accolades dans la syntaxe Shell.
Dans le langage de commande Shell, un jeton qui exécute une fonction de redirection. Il s'agit de l'un des symboles suivants:
< > >| << >> <& >& <<- <>
Ceux-ci vous permettent de contrôler l'entrée et la sortie de vos commandes. Ils peuvent apparaître n'importe où dans une simple commande ou peuvent suivre une commande. Les redirections sont traitées dans l'ordre dans lequel elles apparaissent, de gauche à droite.
<
: Donne une entrée à une commande.
command < file.txt
Ce qui précède exécutera command
sur le contenu de file.txt
.
<>
: Idem que ci-dessus, mais le fichier est ouvert en mode lecture + écriture au lieu de lecture seule:
command <> file.txt
Si le fichier n'existe pas, il sera créé.
Cet opérateur est rarement utilisé parce que les commandes ne sont généralement que - lire à partir de leur stdin, bien que il peut être utile dans un certain nombre de situations spécifiques .
>
: Dirige la sortie d'une commande dans un fichier.
command > out.txt
Ce qui précède enregistrera la sortie de command
sous out.txt
. Si le fichier existe, son contenu sera écrasé et s'il n'existe pas, il sera créé.
Cet opérateur est également souvent utilisé pour choisir si quelque chose doit être imprimé sur erreur standard ou sortie standard :
command >out.txt 2>error.txt
Dans l'exemple ci-dessus, >
Redirigera la sortie standard et 2>
Redirigera l'erreur standard. La sortie peut également être redirigée à l'aide de 1>
Mais, comme il s'agit de la valeur par défaut, le 1
Est généralement omis et il est simplement écrit comme >
.
Ainsi, pour exécuter command
sur file.txt
Et enregistrer sa sortie dans out.txt
Et tous les messages d'erreur dans error.txt
, Vous devez exécuter:
command < file.txt > out.txt 2> error.txt
>|
: Fait la même chose que >
, Mais écrasera la cible, même si le shell a été configuré pour refuser l'écrasement (avec set -C
Ou set -o noclobber
) .
command >| out.txt
Si out.txt
Existe, la sortie de command
remplacera son contenu. S'il n'existe pas, il sera créé.
>>
: Fait la même chose que >
, Sauf que si le fichier cible existe, les nouvelles données sont ajoutées.
command >> out.txt
Si out.txt
Existe, la sortie de command
lui sera ajoutée, après tout ce qui s'y trouve déjà. S'il n'existe pas, il sera créé.
&>
, >&
, >>&
Et &>>
: (Non standard). Redirigez l'erreur standard et la sortie standard, en remplaçant ou en ajoutant respectivement.
command &> out.txt
L'erreur standard et la sortie standard de command
seront enregistrées dans out.txt
, Écrasant son contenu ou le créant s'il n'existe pas.
command &>> out.txt
Comme ci-dessus, sauf que si out.txt
Existe, la sortie et l'erreur de command
y seront ajoutées.
La variante &>
Provient de bash
, tandis que la variante >&
Vient de csh (des décennies plus tôt). Ils sont tous deux en conflit avec d'autres opérateurs POSIX Shell et ne doivent pas être utilisés dans des scripts portables sh
.
<<
: Un document ici. Il est souvent utilisé pour imprimer des chaînes multi-lignes.
command << Word
Text
Word
Ici, command
prendra tout jusqu'à ce qu'il trouve la prochaine occurrence de Word
, Text
dans l'exemple ci-dessus, en entrée. Alors que Word
est souvent EoF
ou des variantes de celui-ci, il peut s'agir de n'importe quelle chaîne alphanumérique (et pas seulement) que vous aimez. Lorsque Word
est cité, le texte du document ici est traité littéralement et aucune expansion n'est effectuée (sur des variables par exemple). S'il n'est pas cité, les variables seront développées. Pour plus de détails, consultez le manuel bash .
Si vous voulez diriger la sortie de command << Word ... Word
Directement dans une ou plusieurs commandes, vous devez placer le tuyau sur la même ligne que << Word
, Vous ne pouvez pas le placer après le mot de fin ou sur la ligne suivante. Par exemple:
command << Word | command2 | command3...
Text
Word
<<<
: Voici des chaînes, similaires aux documents ici, mais destinées à une seule ligne. Ceux-ci n'existent que dans le port Unix ou rc (d'où il provient), zsh, certaines implémentations de ksh, yash et bash.
command <<< Word
Tout ce qui est donné comme Word
est développé et sa valeur est passée en entrée à command
. Ceci est souvent utilisé pour transmettre le contenu des variables en entrée à une commande. Par exemple:
$ foo="bar"
$ sed 's/a/A/' <<< "$foo"
bAr
# as a short-cut for the standard:
$ printf '%s\n' "$foo" | sed 's/a/A/'
bAr
# or
sed 's/a/A/' << EOF
$foo
EOF
Quelques autres opérateurs (>&-
, x>&y
x<&y
) Peuvent être utilisés pour fermer ou dupliquer des descripteurs de fichiers. Pour plus de détails à leur sujet, veuillez consulter la section pertinente du manuel de votre Shell ( ici par exemple pour bash).
Cela ne couvre que les opérateurs les plus courants de coques de type Bourne. Certains shells ont leurs propres opérateurs de redirection supplémentaires.
Ksh, bash et zsh ont également des constructions <(…)
, >(…)
et =(…)
(cette dernière dans zsh
uniquement). Ce ne sont pas des redirections, mais substitution de processus .
Les débutants Unix qui viennent d'apprendre la redirection d'E/S (<
et >
) essaie souvent des choses comme
commander … fichier_entrée > the_same_file
ou
commander … < fichier > the_same_file
ou, presque de manière équivalente,
chat fichier | commander …> the_same_file
(grep
, sed
, cut
, sort
et spell
sont des exemples de commandes que les gens sont tentés d'utiliser dans des constructions comme celles-ci .) Les utilisateurs sont surpris de découvrir que ces scénarios entraînent la vidange du fichier.
Une nuance qui ne semble pas être mentionnée dans l'autre réponse se trouve dans la première phrase de la section Redirection de bash (1) :
Avant qu'une commande ne soit exécutée, ses entrées et sorties peuvent être redirigées en utilisant une notation spéciale interprétée par le Shell.
Les cinq premiers mots doivent être en gras, en italique, soulignés, agrandis, clignotants, colorés en rouge et marqués d'un , pour souligner le fait que le Shell effectue la ou les redirection (s) demandée (s) avant l'exécution de la commande. Et rappelez-vous aussi
La redirection de la sortie entraîne l'ouverture du fichier… pour l'écriture…. Si le fichier n'existe pas, il est créé; s'il existe, il est tronqué à zéro.
Donc, dans cet exemple:
sort roster > roster
le Shell ouvre le fichier roster
pour l'écriture, le tronque (c'est-à-dire en supprimant tout son contenu), avant que le programme sort
ne démarre. Naturellement, rien ne peut être fait pour récupérer les données.
On pourrait naïvement s’attendre à ce que
tr "[:upper:]" "[:lower:]" < poem > poem
pourrait être mieux. Étant donné que le shell gère les redirections de gauche à droite, il ouvre poem
pour la lecture (pour l'entrée standard de tr
) avant de l'ouvrir pour l'écriture (pour la sortie standard). Mais ça n'aide pas. Même si cette séquence d'opérations produit deux descripteurs de fichiers, ils pointent tous deux vers le même fichier. Lorsque le shell ouvre le fichier pour lecture, le contenu est toujours là, mais il est toujours encombré avant l'exécution du programme.
Les solutions comprennent:
Vérifiez si le programme que vous exécutez a sa propre capacité interne pour spécifier où va la sortie. Ceci est souvent indiqué par un -o
(ou --output=
) jeton. En particulier,
sort roster -o roster
est à peu près équivalent à
sort roster > roster
sauf que, dans le premier cas, le programme sort
ouvre le fichier de sortie. Et il est suffisamment intelligent pour ne pas ouvrir le fichier de sortie tant que après il n'a pas lu tous les fichiers d'entrée.
De même, au moins certaines versions de sed
ont un -i
(Éditer jen place) option qui peut être utilisée pour réécrire la sortie dans le fichier d'entrée (encore une fois, après toutes les entrées ont été lues). Les éditeurs comme ed
/ex
, emacs
, pico
et vi
/vim
permettent à l'utilisateur de modifier un fichier texte et enregistrez le texte modifié dans le fichier d'origine. Notez que ed
(au moins) peut être utilisé de manière non interactive.
vi
a une fonction connexe. Si vous tapez :%!command
Enter, il écrira le contenu du tampon d'édition dans command
, lira la sortie et l'insérera dans le tampon (en remplaçant le contenu d'origine).Simple mais efficace:
commander … fichier_entrée > fichier_temp && mv fichier_tempfichier_entrée
Cela présente l'inconvénient que, si input_file
est un lien, il sera (probablement) remplacé par un fichier séparé. De plus, le nouveau fichier vous appartiendra, avec des protections par défaut. En particulier, cela comporte le risque que le fichier finisse par être lisible par tout le monde, même si l'original input_file
ne l'était pas.
Variations:
command … input_file > temp_file && cp temp_fileinput_file && rm temp_file
temp_file
lisible dans le monde entier. Encore mieux:cp input_filetemp_file && command … temp_file > input_file && rm temp_file
-a
ou -p
on cp
pour lui dire de conserver les attributs.)command … input_file > temp_file &&
cp --attributes-only --preserve=all input_filetemp_file &&
mv temp_fileinput_file
Ce blog (édition "sur place" des fichiers) suggère et explique
{rm fichier_entrée && commander …> fichier_entrée; } < fichier_entrée
Cela nécessite que le command
puisse traiter l'entrée standard (mais presque tous les filtres le peuvent). Le blog lui-même appelle cela un coup de tête risqué et décourage son utilisation. Et cela créera également un nouveau fichier séparé (non lié à quoi que ce soit), détenu par vous et avec des autorisations par défaut.
Le paquet moreutils a une commande appelée sponge
:
commander … fichier_entrée | éponge the_same_file
Voir cette réponse pour plus d'informations.
Voici quelque chose qui m'a complètement surpris: erreur de syntaxe :
[La plupart de ces solutions] échouera sur un système de fichiers en lecture seule, où "lecture seule" signifie que votre
$HOME
le sera être accessible en écriture, mais/tmp
sera en lecture seule (par défaut). Par exemple, si vous avez Ubuntu et que vous avez démarré dans la console de récupération, c'est généralement le cas. L'opérateur ici-document<<<
ne fonctionnera pas non plus, car cela nécessite/tmp
être en lecture/écriture car il y écrira également un fichier temporaire.
(cf.. cette question inclut une sortiestrace
’d)
Les éléments suivants peuvent fonctionner dans ce cas:
sort
, ou tr
sans le -d
ou -s
option), vous pouvez essayer commander … fichier_entrée | jj de =the_same_file conv = notruncVoir cette réponse et cette réponse pour plus d'informations, y compris une explication de ce qui précède, et des alternatives qui fonctionnent si votre commande est garantie de produire la même quantité des données de sortie lorsqu'elles sont entrées ou moins (par exemple,
grep
, ou cut
). Ces réponses ont l'avantage de ne pas nécessiter d'espace libre (ou très peu). Les réponses ci-dessus du formulaire command … input_file > temp_file && …
exige clairement qu'il y ait suffisamment d'espace libre pour que le système puisse contenir le fichier d'entrée (ancien) et le fichier de sortie (nouveau) simultanément; cela n'est pas évidemment vrai pour la plupart des autres solutions (par exemple, sed -i
et sponge
) également. Exception: sort … | dd …
nécessitera probablement beaucoup d'espace libre, car sort
doit lire toutes ses entrées avant de pouvoir écrire n'importe quelle sortie, et il met probablement en mémoire tampon la plupart sinon la totalité de ces données dans un fichier temporaire.commander … fichier_entrée 1 <> the_same_filepeut être équivalent à la réponse
dd
ci-dessus. Le n<>file
la syntaxe ouvre le fichier nommé sur le descripteur de fichier n
pour l'entrée et la sortie, sans le tronquer - une sorte de combinaison de n<
et n>
. Remarque: Certains programmes (par exemple, cat
et grep
) peuvent refuser de s'exécuter dans ce scénario car ils peuvent détecter que l'entrée et la sortie sont le même fichier. Voir cette réponse pour une discussion de ce qui précède, et un script qui fait fonctionner cette réponse si votre commande est garantie de produire la même quantité de données de sortie qu'il y a d'entrée ou moins.Cela a été un sujet populaire sur U&L; il est abordé dans les questions suivantes:
iconv
remplace le fichier d'entrée par la sortie convertie?shuf file > file
laisser un fichier vide?sort
me donne-t-elle un fichier vide?tr
stdout vers un fichier… Et cela ne compte pas le super utilisateur ou Ask Ubuntu. J'ai incorporé une grande partie des informations des réponses aux questions ci-dessus ici dans cette réponse, mais pas toutes. (C'est-à-dire, pour plus d'informations, lisez les questions ci-dessus et leurs réponses.)
P.S. Je n'ai aucune affiliation avec le blog que j'ai cité ci-dessus.
;
, &
, (
et )
Notez que certaines des commandes de la réponse de terdon peuvent être nulles. Par exemple, vous pouvez dire
command1 ;
(sans command2
). Cela équivaut à
command1
(c'est-à-dire qu'il exécute simplement command1
au premier plan et attend qu'il se termine. En comparaison,
command1 &
(sans command2
) Va lancer command1
en arrière-plan, puis émettez immédiatement une autre invite Shell.
Par contre, command1 &&
, command1 ||
, et command1 |
ça n'a aucun sens. Si vous en saisissez une, le Shell supposera (probablement) que la commande se poursuit sur une autre ligne. Il affichera l'invite du shell secondaire (suite), qui est normalement définie sur >
, et continuez à lire. Dans un script Shell, il va simplement lire la ligne suivante et l'ajouter à ce qu'il a déjà lu. (Attention: ce n'est peut-être pas ce que vous voulez.)
Remarque: certaines versions de certains shells peuvent traiter ces commandes incomplètes comme des erreurs. Dans de tels cas (ou, en fait, dans tout cas où vous avez une commande longue), vous pouvez mettre une barre oblique inverse (\
) à la fin d'une ligne pour indiquer au shell de continuer à lire la commande sur une autre ligne:
command1 && \
command2
ou
find starting-directory -mindepth 3 -maxdepth 5 -iname "*.some_extension" -type f \
-newer some_existing_file -user fred -readable -print
Comme le dit terdon, (
et )
peut être utilisé pour regrouper des commandes. L'affirmation selon laquelle ils "ne sont pas vraiment pertinents" pour cette discussion est discutable. Certaines des commandes de la réponse de terdon peuvent être la commande groups. Par exemple,
( command1 ; command2 ) && ( command3; command4 )
est ce que ca:
command1
et attendez qu'il se termine.command2
et attendez qu'il se termine.Puis si command2
réussi,
command3
et attendez qu'il se termine.command4
et attendez qu'il se termine.Si command2
a échoué, arrêtez de traiter la ligne de commande.
Parenthèses extérieures, |
se lie très étroitement, donc
command1 | command2 || command3
est équivalent à
( command1 | command2 ) || command3
et &&
et ||
lier plus fort que ;
, donc
command1 && command2 ; command3
est équivalent à
( command1 && command2 ) ; command3
c'est à dire., command3
sera exécuté quel que soit l'état de sortie de command1
et/ou command2
.