Le tuyau est utilisé pour transmettre la sortie à un autre programme ou utilitaire .
La redirection est utilisée pour transmettre la sortie à un fichier ou à un flux .
Exemple: thing1 > thing2
vsthing1 | thing2
thing1 > thing2
- Votre shell exécutera le programme nommé
thing1
- Tout ce qui
thing1
sort sera placé dans un fichier appelé thing2
. (Remarque - s'il thing2
existe, il sera écrasé)
Si vous souhaitez transmettre le résultat d'un programme thing1
à un programme appelé thing2
, vous pouvez procéder comme suit:
thing1 > temp_file && thing2 < temp_file
qui ferait
- exécuter le programme nommé
thing1
- enregistrer la sortie dans un fichier nommé
temp_file
- exécutez le programme nommé
thing2
en prétendant que la personne au clavier a saisi le contenu de en temp_file
tant qu'entrée.
Cependant, c'est maladroit, alors ils ont fabriqué des pipes comme un moyen plus simple de le faire. thing1 | thing2
fait la même chose quething1 > temp_file && thing2 < temp_file
EDIT pour fournir plus de détails à la question dans le commentaire:
Si vous >
essayez d’être à la fois "passer au programme" et "écrire dans un fichier", cela pourrait poser des problèmes dans les deux sens.
Premier exemple: vous essayez d'écrire dans un fichier. Il existe déjà un fichier portant ce nom que vous souhaitez écraser. Cependant, le fichier est exécutable. Vraisemblablement, il essaierait d'exécuter ce fichier en transmettant l'entrée. Vous devez faire quelque chose comme écrire la sortie dans un nouveau nom de fichier, puis renommer le fichier.
Deuxième exemple: comme Florian Diesch l'a fait remarquer, que se passe-t-il s'il existe une autre commande du même nom ailleurs dans le système (c'est-à-dire dans le chemin d'exécution)? Si vous aviez l'intention de créer un fichier portant ce nom dans votre dossier actuel, vous seriez bloqué.
Troisièmement: si vous tapez mal une commande, cela ne vous avertirait pas que la commande n'existe pas. En ce moment, si vous tapez, ls | gerp log.txt
cela vous le dira bash: gerp: command not found
. Si cela >
signifiait les deux, il créerait simplement un nouveau fichier pour vous (alors avertissez-le, il ne sait pas quoi faire avec log.txt
).
thing1 > temp_file && thing2 < temp_file
de faire plus facilement avec des pipes. Mais pourquoi ne pas réutiliser l'>
opérateur pour le faire, par exemplething1 > thing2
pour les commandesthing1
etthing2
? Pourquoi un opérateur supplémentaire|
?less
, par exemple?thing | less
etthing > less
sont parfaitement différents, comme ils font des choses différentes. Ce que vous proposez créerait une ambiguïté.tee
commande fait quelque chose de différent.tee
écrit la sortie sur l’écran (stdout
) et le fichier. La redirection ne concerne que le fichier.Si la signification de
foo > bar
dépend de si une commande nomméebar
rend l'utilisation de la redirection beaucoup plus difficile et plus sujette aux erreurs: chaque fois que je veux rediriger vers un fichier, je dois d'abord vérifier s'il existe une commande nommée comme mon fichier de destination.la source
bar
dans un répertoire faisant partie de votre$PATH
variable env. Si vous êtes dans quelque chose comme / bin, alors ça pourrait être un problème. Mais même dans ce cas, ilbar
faudrait un ensemble d'autorisations exécutables, de sorte que le shell vérifie non seulement de trouver un exécutable,bar
mais peut également l'exécuter. Et si le problème concerne le remplacement du fichier existant, l’noclober
option shell devrait empêcher d’écraser les fichiers existants dans les redirections.Du manuel d’administration du système Unix et Linux:
Donc, mon interprétation est la suivante: si commande à commande, utilisez un tuyau. Si vous exportez depuis ou vers un fichier, utilisez la redirection.
la source
Il y a une différence vitale entre les deux opérateurs:
ls > log.txt
-> Cette commande envoie la sortie au fichier log.txt.ls | grep file.txt
-> Cette commande envoie le résultat de la commande ls à grep par le biais de pipe (|
), et la commande grep recherche file.txt dans l'entrée fournie par la commande précédente.Si vous deviez effectuer la même tâche en utilisant le premier scénario, alors ce serait:
Ainsi, un tuyau (avec
|
) est utilisé pour envoyer la sortie à une autre commande, alors que la redirection (avec>
) est utilisé pour rediriger la sortie vers un fichier.la source
Il y a une grande différence syntaxique entre les deux:
Vous pouvez penser réoriente comme ceci:
cat [<infile] [>outfile]
. Cela implique que l'ordre n'a pas d'importance:cat <infile >outfile
est le même quecat >outfile <infile
. Vous pouvez même mélanger les redirections avec d'autres arguments:cat >outfile <infile -b
et cela vacat <infile -b >outfile
parfaitement. Vous pouvez également enchaîner plus d'une entrée ou de sortie (entrées seront lues séquentiellement et toutes les sorties seront écrites à chaque fichier de sortie):cat >outfile1 >outfile2 <infile1 <infile2
. La cible ou la source d'une redirection peut être un nom de fichier ou le nom d'un flux (comme & 1, au moins en bash).Mais les tubes séparent totalement une commande d'une autre, vous ne pouvez pas les mélanger avec des arguments:
Le tube prend tout ce qui est écrit dans la sortie standard de commande1 et l'envoie à l'entrée standard de commande2.
Vous pouvez également combiner la tuyauterie et la redirection. Par exemple:
Le premier
cat
lit les lignes depuis infile, puis écrit simultanément chaque ligne dans outfile et l'envoie à la secondecat
.Dans la seconde
cat
, l’entrée standard lit d’abord dans le tuyau (le contenu d’infile), puis dans infile2, en écrivant chaque ligne dans outfile2. Après avoir exécuté ceci, outfile sera une copie de infile, et outfile2 contiendra infile suivi de infile2.Enfin, vous faites quelque chose de vraiment similaire à votre exemple en utilisant la redirection "here string" (famille bash uniquement) et des backticks:
donnera le même résultat que
Mais je pense que la version de redirection lira d’abord toute la sortie de ls dans un tampon (en mémoire), puis alimentera ce tampon dans une ligne à la fois pour grep, alors que la version canalisée prendra chaque ligne de ls au fur et à mesure, et passez cette ligne à grep.
la source
echo yes 1>&2 2>/tmp/blah; wc -l /tmp/blah; echo yes 2>/tmp/blah 1>&2; wc -l /tmp/blah
De plus, la redirection vers un fichier n’utilisera que la dernière redirection.echo yes >/tmp/blah >/tmp/blah2
va seulement écrire à/tmp/blah2
.Remarque: la réponse reflète ma propre compréhension de ces mécanismes actualisés, accumulés au cours de la recherche et de la lecture des réponses par les pairs sur ce site et sur unix.stackexchange.com , et sera mise à jour au fil du temps. N'hésitez pas à poser des questions ou à suggérer des améliorations dans les commentaires. Je vous suggère également d'essayer de voir comment les appels système fonctionnent en shell avec
strace
commande. Veuillez également ne pas être intimidé par la notion d'internes ou d'appels système - vous n'avez pas besoin de savoir ou de pouvoir les utiliser pour comprendre comment fonctionne un shell, mais ils aident vraiment à la compréhension.TL; DR
|
Les pipes ne sont pas associées à une entrée sur le disque, donc n’ont pas de numéro de système de fichiers sur le disque (mais ont un inode dans le système de fichiers virtuel pipefs dans l’espace noyau), mais les redirections impliquent souvent des fichiers qui ont des entrées de inode.lseek()
'capables, donc les commandes ne peuvent pas lire certaines données et ensuite revenir en arrière, mais quand vous redirigez avec>
ou<
habituellement c'est un fichier qui est unlseek()
objet capable, les commandes peuvent donc naviguer comme bon leur semble.dup2()
appels système sous le capot pour fournir des copies des descripteurs de fichier, où le flux réel de données se produit.exec
commande intégrée (voir ceci et cela ), donc si vous le faites,exec > output.txt
chaque commande écrit àoutput.txt
partir de là.|
Les tuyaux ne sont appliqués que pour la commande en cours (ce qui signifie soit une commande simple, soit des commandes semblables à un sous-shellseq 5 | (head -n1; head -n2)
ou composées.Lorsque la redirection est effectuée sur des fichiers, des choses comme
echo "TEST" > file
etecho "TEST" >> file
toutes les deux utilisentopen()
syscall sur ce fichier ( voir aussi ) et en tirent le descripteur de fichierdup2()
. Les pipes|
n'utilisent quepipe()
etdup2()
syscall.En ce qui concerne les commandes en cours d'exécution, les canaux et la redirection ne sont rien de plus que des descripteurs de fichier - des objets de type fichier, sur lesquels ils peuvent écrire en aveugle ou les manipuler en interne (ce qui peut produire des comportements inattendus;
apt
par exemple, a tendance à ne même pas écrire sur stdout s'il sait qu'il y a redirection).introduction
Afin de comprendre en quoi ces deux mécanismes diffèrent, il est nécessaire de comprendre leurs propriétés essentielles, leur histoire et leurs racines dans le langage de programmation C. En fait, savoir ce que sont les descripteurs de fichier, comment
dup2()
et comment lespipe()
appels système fonctionnent est essentiellseek()
. Shell est conçu comme un moyen de rendre ces mécanismes abstraits pour l'utilisateur, mais creuser plus profondément que l'abstraction permet de comprendre la vraie nature du comportement de shell.Les origines des redirections et des pipes
Selon l'article de Dennis Ritche, Prophetic Petroglyphs , les tuyaux proviennent d'une note interne de Malcolm Douglas McIlroy , datant de 1964 , à l'époque où ils travaillaient sur le système d'exploitation Multics . Citation:
Ce qui est évident, c’est qu’à l’époque, les programmes étaient capables d’écrire sur disque, mais c’était inefficace si la sortie était volumineuse. Pour citer l'explication de Brian Kernighan dans la vidéo Unix Pipeline :
La différence conceptuelle est donc évidente: les pipes sont un mécanisme permettant aux programmes de se parler. Les redirections - sont une façon d'écrire dans un fichier au niveau de base. Dans les deux cas, Shell facilite ces deux choses, mais sous le capot, il se passe beaucoup de choses.
Aller plus loin: appels système et fonctionnement interne du shell
Nous commençons par la notion de descripteur de fichier . Les descripteurs de fichier décrivent essentiellement un fichier ouvert (qu'il s'agisse d'un fichier sur disque, en mémoire ou anonyme), qui est représenté par un nombre entier. Les deux flux de données standard (stdin, stdout, stderr) sont respectivement les descripteurs de fichier 0,1 et 2. D'où viennent-ils ? Dans les commandes shell, les descripteurs de fichier sont hérités de leur parent - shell. Et c'est vrai en général pour tous les processus - le processus enfant hérite des descripteurs de fichier du parent. Pour les démons, il est courant de fermer tous les descripteurs de fichiers hérités et / ou de les rediriger vers d'autres emplacements.
Retour à la redirection. C'est quoi vraiment? C'est un mécanisme qui indique au shell de préparer les descripteurs de fichier pour la commande (car les redirections sont effectuées par le shell avant l'exécution de la commande), et de les indiquer à l'endroit suggéré par l'utilisateur. La définition standard de la redirection de sortie est
Qu'il
[n]
y ait le numéro de descripteur de fichier. Lorsque vous faitesecho "Something" > /dev/null
le numéro 1 est implicite là, etecho 2> /dev/null
.Sous le capot, cela se fait en dupliquant le descripteur de fichier via
dup2()
un appel système. Prenonsdf > /dev/null
. Le shell créera un processus enfant oùdf
s'exécutera, mais avant cela, il s'ouvrira en/dev/null
tant que descripteur de fichier n ° 3 etdup2(3,1)
sera publié. Il créera une copie du descripteur de fichier 3 et la copie sera 1. Vous savez comment vous avez deux fichiersfile1.txt
etfile2.txt
et quand vouscp file1.txt file2.txt
aurez deux fichiers identiques, mais que vous pourrez les manipuler indépendamment? C'est un peu la même chose qui se passe ici. Souvent, vous pouvez voir que, avant de lancer la tâche,bash
il estdup(1,10)
nécessaire de créer un descripteur de fichier de copie n ° 1 qui eststdout
(et que cette copie sera le disque n ° 10) afin de le restaurer ultérieurement. Il est important de noter que lorsque vous considérez les commandes intégrées(qui font partie du shell proprement dit, et n'ont aucun fichier/bin
dedans ou ailleurs) ou de simples commandes dans un shell non interactif , le shell ne crée pas de processus enfant.Et puis nous avons des choses comme
[n]>&[m]
et[n]&<[m]
. Cela duplique les descripteurs de fichier, dont le mécanisme est identique àdup2()
celui de la syntaxe du shell, disponible pour l'utilisateur.Un des points importants à noter à propos de la redirection est que leur ordre n’est pas fixe, mais qu’il est important pour l’interprétation que shell donne à ce que l’utilisateur souhaite. Comparez ce qui suit:
L'utilisation pratique de ceux-ci dans les scripts shell peut être polyvalente:
et beaucoup d'autres.
Plomberie avec
pipe()
etdup2()
Alors, comment les tuyaux sont-ils créés? Via
pipe()
syscall , qui prendra en entrée un tableau (ou liste) appelépipefd
de deux éléments de typeint
(entier). Ces deux entiers sont des descripteurs de fichier. Lepipefd[0]
sera l'extrémité de lecture du tuyau etpipefd[1]
sera l'extrémité d'écriture. So indf | grep 'foo'
,grep
obtiendra une copiepipefd[0]
etdf
obtiendra une copie depipefd[1]
. Mais comment ? Bien sûr, avec la magie de l'dup2()
appel système. Pardf
exemple, dans notre exemple,pipefd[1]
a # 4, le shell fera un enfant, dodup2(4,1)
(souvenez-vous de moncp
exemple?), Puisexecve()
exécutezdf
. Naturellement,df
héritera du descripteur de fichier n ° 1, mais ne saura pas qu'il ne pointe plus sur le terminal, mais sur le fichier fd n ° 4, qui correspond en réalité à la fin du tuyau. Naturellement, la même chose se produiragrep 'foo'
sauf avec des nombres différents de descripteurs de fichiers.Maintenant, question intéressante: pourrions-nous aussi créer des pipes qui redirigeront fd # 2, pas seulement fd # 1? Oui, en fait, c'est ce qui se
|&
passe à Bash. La norme POSIX exige que le langage de commande shell prenne en charge ladf 2>&1 | grep 'foo'
syntaxe à cette fin, mais il enbash
va|&
de même.Il est important de noter que les pipes traitent toujours avec des descripteurs de fichier. Il existe
FIFO
ou pipe nommée , qui a un nom de fichier sur le disque et vous permet de l'utiliser comme un fichier, mais se comporte comme une pipe. Mais les|
types de canaux sont ce qu’on appelle des tubes anonymes - ils n’ont pas de nom de fichier, car ce ne sont en réalité que deux objets reliés entre eux. Le fait que nous n'ayons pas affaire à des fichiers a également une implication importante: les pipes ne sont paslseek()
capables. Les fichiers, en mémoire ou sur disque, sont statiques - les programmes peuvent utiliserlseek()
syscall pour passer à l'octet 120, puis revenir à l'octet 10, puis le transférer à la fin. Les pipes ne sont pas statiques - elles sont séquentielles, et vous ne pouvez donc pas rembobiner les données que vous obtenez aveclseek()
. C’est ce qui permet à certains programmes de savoir s’ils lisent à partir d’un fichier ou d’un tuyau, et peuvent donc effectuer les ajustements nécessaires pour obtenir des performances efficaces; en d'autres termes, unprog
peut détecter si je le faiscat file.txt | prog
ouprog < input.txt
. Le vrai exemple de travail est la queue .Les deux autres propriétés très intéressantes des pipes sont qu’elles ont un tampon, ce qui sous Linux est de 4096 octets , et qu’elles ont un système de fichiers tel que défini dans le code source de Linux ! Ils ne sont pas simplement un objet de transmission de données, ils sont eux-mêmes une structure de données! En fait, comme il existe un système de fichiers pipefs, qui gère à la fois les tubes et les FIFO, les tubes ont un numéro inode sur leur système de fichiers respectif:
Sur Linux, les canaux sont unidirectionnels, tout comme la redirection. Sur certaines implémentations de type Unix, il existe des tuyaux bidirectionnels. Bien qu'avec la magie des scripts shell, vous pouvez également créer des pipes bidirectionnelles sur Linux .
Voir également:
pipe()
syscall etdup2()
.<<
,<<<
sont implémentées en tant que fichiers temporaires anonymes (non liés) dansbash
etksh
, tout en< <()
utilisant des canaux anonymes;/bin/dash
utilise des tuyaux pour<<
. Voir Quelle est la différence entre <<, <<< et <<in bash?la source
Pour ajouter aux autres réponses, il existe également une différence sémantique subtile - par exemple, les tuyaux se ferment plus facilement que les redirections:
Dans le premier exemple, lorsque le premier appel à
head
terminer se termine, il ferme le tuyau et seseq
termine, il n'y a donc aucune entrée disponible pour le secondhead
.Dans le second exemple, head utilise la première ligne, mais lorsqu'il ferme son propre
stdin
canal , le fichier reste ouvert pour le prochain appel à utiliser.Le troisième exemple montre que si nous utilisons
read
pour éviter de fermer le canal, celui-ci est toujours disponible dans le sous-processus.Donc, le "flux" est la chose par laquelle nous shuntons des données (stdin, etc.), et est identique dans les deux cas, mais le canal connecte les flux de deux processus, où une redirection connecte un flux entre un processus et un fichier. peut voir la source des similitudes et des différences.
PS Si vous êtes aussi curieux et / ou surpris par ces exemples que moi, vous pouvez aller plus loin en
trap
vous montrant comment les processus se résolvent, par exemple:Parfois, le premier processus se ferme avant d'
1
être imprimé, parfois après.J'ai aussi trouvé intéressant de
exec <&-
fermer le flux de la redirection pour se rapprocher du comportement du canal (avec une erreur toutefois):la source
read
consomme uniquement la première ligne (c'est un octet pour1
et une nouvelle ligne).seq
envoyé au total 10 octets (5 numéros et 5 nouvelles lignes). Il reste donc 8 octets dans le tampon de canal, et c’est pourquoi secondhead
fonctionne: il reste des données dans le tampon de canal. Au fait, la tête ne sort que s'il y a 0 octets lus, un peu comme danshead /dev/null
seq 5 | (head -n1; head -n1)
du premier appel, le canal est vidé, de sorte qu'il existe toujours à l'état ouvert, mais sans données pour le deuxième appel àhead
? La différence de comportement entre le tube et la redirection est donc due au fait que head extrait toutes les données du tube, mais uniquement les 2 lignes du fichier.strace
commande que j'ai donnée dans le premier commentaire. Avec la redirection, le fichier tmp se trouve sur le disque, ce qui le rend utilisable (car ils utilisentlseek()
syscall - les commandes permettent de contourner le fichier du premier au dernier octet comme bon leur semble. Mais les canaux sont séquentiels et non recherchables. Le travail consiste à tout lire en premier, ou si le fichier est gros - en mapper une partie à la RAM via unmmap()
appel. J'ai déjà fait le mientail
en Python et j'ai rencontré exactement le même problème.(...)
-shell, qui effectuera une copie de son propre stdin pour chaque commande qu'il contient(...)
. Donc, techniquement, ils sont lus à partir du même objet.head
Pense d' abord qu'il lit à partir de son propre stdin. Secondhead
pense avoir son propre stdin. Mais en réalité, leur fd # 1 (stdin) est une copie du même fd, qui est lu à la fin du tube. De plus, j'ai posté une réponse, alors peut-être que ça va aider à clarifier les choses.J'ai rencontré un problème avec cela en C aujourd'hui. Essentiellement, les tuyaux ont une sémantique différente vers les redirections, même lorsqu'ils sont envoyés à
stdin
. Vraiment , je pense qu'étant donné les différences, les tuyaux doivent aller quelque part ailleurs questdin
, de sorte questdin
et laisse l' appelerstdpipe
(pour faire un différentiel arbitraire) peuvent être traitées de différentes façons.Considère ceci. Lorsque la tuyauterie d' une sortie de programme à l' autre
fstat
semble revenir zéro commest_size
malgréls -lha /proc/{PID}/fd
montre qu'il ya un fichier. Lors de la redirection d'un fichier, ce n'est pas le cas (du moins sur debianwheezy
,stretch
etjessie
vanilla et ubuntu14.04
,16.04
vanilla.Si vous
cat /proc/{PID}/fd/0
utilisez une redirection, vous pourrez répéter la lecture autant de fois que vous le souhaitez. Si vous faites cela avec un tuyau, vous remarquerez que la deuxième fois que vous exécutez la tâche consécutivement, vous n'obtenez pas le même résultat.la source