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 | ???
19
demandé sur Kairan 2012-10-17 23:37:26

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).

20
répondu ruakh 2012-10-17 19:45:40

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).

13
répondu rici 2012-10-17 20:07:48

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 que in1.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, seulement out2.txt contiendra le contenu de out2.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é.

3
répondu doubleDown 2017-05-23 12:07:16

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.

3
répondu Mark Edgar 2012-10-20 20:56:47

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.
1
répondu sampson-chen 2012-10-17 19:47:17