Priorité Pipe / Redirection
je veux préciser quand le pipe / ou la redirection a priorité dans une commande?
c'est ma pensée mais j'ai besoin de confirmation c'est comme ça que ça marche.
exemple 1:
sort < names | head
The pipe runs first: names|head then it sorts what is returned from names|head
exemple 2:
ls | sort > out.txt
This one seems straight forward by testing, ls|sort then redirects to out.txt
exemple 3:
Fill in the blank? Can you have both a < and a > with a | ???
5 réponses
En termes de regroupement syntaxique, >
et <
ont une priorité plus élevée; en effet, ces deux commandes sont équivalentes:
sort < names | head
( sort < names ) | head
comme ces deux-là:
ls | sort > out.txt
ls | ( sort > out.txt )
mais en termes d'ordre séquentiel,|
est exécutée en premier; donc, cette commande:
cat in.txt > out1.txt | cat > out2.txt
remplir out1.txt
, pas out2.txt
, parce que le > out1.txt
est exécuté après|
et donc remplace (donc pas de sortie est les canalisations à cat > out2.txt
).
de Même, cette commande:
cat < in1.txt | cat < in2.txt
print in2.txt
, pas in1.txt
, parce que le < in2.txt
est exécuté après|
et donc remplace (si aucune entrée n'est canalisée à partir de cat < in1.txt
).
man bash
(comme le sont les autres citations):
SHELL GRAMMAR
Simple Commands
A simple command is a sequence of optional variable assignments followed by
blank-separated words and redirections, and terminated by a control
operator. The first word specifies the command to be executed, and is
passed as argument zero. The remaining words are passed as arguments
to the invoked command.
The return value of a simple command is its exit status, or 128+n if
the command is terminated by signal n.
Pipelines
A pipeline is a sequence of one or more commands separated by one of
the control operators | or |&. The format for a pipeline is:
[time [-p]] [ ! ] command [ [|⎪|&] command2 ... ]
en d'autres termes, vous pouvez avoir n'importe quel nombre de redirections pour une commande (simple); vous pouvez aussi l'utiliser comme partie d'un pipeline. Ou, en d'autres termes, la redirection se lie plus étroitement que le tuyau.
il y a plusieurs façons de contourner ce problème (bien qu'elles soient rarement nécessaires ou esthétiques):
1.
vous pouvez faire une "commande composée" et rediriger vers c':
Compound Commands
A compound command is one of the following:
(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 metacharacters ( 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 metacharacter.
Donc:
$ echo foo > input
$ { cat | sed 's/^/I saw a line: /'; } < input
I saw a line: foo
2.
Vous pouvez rediriger vers un tuyau à l'aide de "processus de substitution":
Process Substitution
Process substitution is supported on systems that support named pipes
(FIFOs) or the /dev/fd method of naming open files. It takes the form of
<(list) or >(list). The process list is run with its input or output
connected to a FIFO or some file in /dev/fd. The name of this file is
passed as an argument to the current command as the result of the
expansion. If the >(list) form is used, writing to the file will provide
input for list. If the <(list) form is used, the file passed as an argument
should be read to obtain the output of list.
Donc:
rici@...$ cat > >(sed 's/^/I saw a line: /') < <(echo foo; echo bar)
I saw a line: foo
rici@...$ I saw a line: bar
(pourquoi l'invite apparaît avant la fin de la sortie, et que faire à ce sujet sont laissés comme des exercices).
C'est à peu près ce que je comprends après avoir lu (y compris ruakh's réponse)
tout D'abord, si vous redirigez plusieurs fois, toutes les redirections sont effectuées, mais seule la dernière redirection prendra effet (en supposant qu'aucune des redirections précédentes ne cause d'erreur)
e.g.
cat < in1.txt < in2.txt
est équivalent àcat < in2.txt
, à moins quein1.txt
n'existe pas, auquel cas cette commande échoue (car< in1.txt
est effectué premier)de Même, avec
cat in.txt > out1.txt > out2.txt
, seulementout2.txt
contiendra le contenu deout2.txt
, mais depuis> out1.txt
a été effectuée en premier,out1.txt
serait créé s'il n'existait pas.
ce que fait pipe est de connecter le stdout
de la commande précédente pour l' stdin
de la commande suivante, et cette connexion vient avant toute autre redirection (de manuel Bash).
pour que vous puissiez penser
cat in1.txt > out1.txt | cat > out2.txt
cat in1.txt > pipe > out1.txt; cat < pipe > out2.txt
et en appliquant la règle de redirection multiple mentionnée précédemment, nous pouvons simplifier cela à
cat in1.txt > out1.txt; cat < pipe > out2.txt
Résultat: Le contenu de in1.txt
copié out1.txt
, puisque rien n'a été écrit à pipe
En utilisant un autre de ruakhl'exemple de la,
cat < in1.txt | cat > in2.txt
est équivalent à
cat > pipe < in1.txt; cat < pipe < in2.txt
ce qui est effectivement
cat > pipe < in1.txt; cat < in2.txt
Résultat: Cette fois, quelque chose est écrit dans le pipe
, mais depuis la seconde cat
lit in2.txt
au lieu de pipe
, seul le contenu de in2.txt
est imprimé.
il est un peu peu peu orthodoxe, mais parfaitement légal, pour placer le <
n'importe où vous le souhaitez, je préfère ce qu'il illustre le mieux la gauche-à-droite pour les flux de données:
<input.txt sort | head >output.txt
la seule fois où vous ne pouvez pas faire cela est avec les commandes de structure de contrôle intégrées (for
,if
,while
).
# Unfortunately, NOT LEGAL
<input.txt while read line; do ...; done
notez que toutes ces commandes sont équivalentes, mais pour éviter toute confusion, n'utilisez que la première ou la dernière:
<input.txt grep -l foobar
grep <input.txt -l foobar
grep -l <input.txt foobar
grep -l foobar <input.txt
parce que le nom du fichier doit toujours venir directement après l'opérateur de redirection, je préfère laisser l'option de l'espace entre le <
et le nom de fichier.
Corrections:
exemple 1:
sort < names | head
dans ce cas, la redirection d'entrée s'exécute en premier (les noms sont triés), puis le résultat est acheminé à head.
En général, on peut lire de gauche à droite. La norme de langage fonctionne comme suit:
- utilisation de la redirection des entrées " < " indique que le programme lit à partir d'un fichier au lieu de stdin
- utilisation de la redirection de sortie " > " indique au programme de sortir dans un fichier au lieu de stdout
- utilisation de la pipe "program_a / program_b" prend tout ce qui serait normalement produit par program_a à stdout, et l'alimente directement à program_b comme s'il avait été lu à partir de stdin.