Les utilitaires Linux sont-ils intelligents lors de l'exécution de commandes piped?

23

J'étais juste en train d'exécuter quelques commandes dans un terminal et j'ai commencé à me demander, est-ce qu'Unix / Linux prend des raccourcis lors de l'exécution de commandes piped?

Par exemple, disons que j'ai un fichier avec un million de lignes, dont les 10 premières contiennent hello world. Si vous exécutez la commande, grep "hello world" file | headla première commande s'arrête-t-elle dès qu'elle trouve 10 lignes ou continue-t-elle de rechercher d'abord le fichier entier?

Chèvre mécontente
la source
2
C'est pourquoi gnu grep a l' -margument.
Paul Tomblin
3
Le terminal n'y est pour rien. Les commandes canalisées sont gérées par le shell.
Keith Thompson
@KeithThompson pardonne mon ignorance, je ne suis pas grand sur la terminologie, je ne savais pas s'il fallait l'appeler terminal, shell ou ligne de commande. N'hésitez pas à suggérer des modifications à ma question :)
DisgruntledGoat

Réponses:

30

Sorte de. Le shell n'a aucune idée de ce que feront les commandes que vous exécutez, il connecte simplement la sortie de l'un à l'entrée de l'autre.

Si greptrouve plus de 10 lignes qui disent "bonjour le monde", alors headil aura les 10 lignes qu'il veut et fermez le tuyau. Cela entraînera grepla mort avec un SIGPIPE, il n'a donc pas besoin de continuer à analyser un fichier très volumineux.

psusi
la source
2
Donc je suppose qu'en raison des conditions de course, grep a peut-être déjà lu le 11ème ou le 12ème motif, mais probablement pas le 100 millième?
utilisateur inconnu
3
Cela dépend en partie de la longueur des lignes et de la taille de la mémoire tampon de tuyau, mais la réponse courte est que grep lira une quantité raisonnablement limitée de données supplémentaires avant d'être tué.
dmckee
1
@userunknown, exactement.
psusi
Cool, je ne savais pas que c'était arrivé. Je pensais grepcontinuer à envoyer la sortie dans un vide, similaire à/dev/null
Izkata
15

Lorsqu'un programme essaie d'écrire sur un canal et qu'il n'y a pas de lecture de processus à partir de ce canal, le programme d'écriture reçoit un signal SIGPIPE . L'action par défaut lorsqu'un programme reçoit SIGPIPE est de terminer le programme. Un programme peut choisir d'ignorer le signal SIGPIPE, auquel cas l'écriture renvoie une erreur ( EPIPE).

Dans votre exemple, voici une chronologie de ce qui se passe:

  • Les commandes grepet headdémarrent en parallèle.
  • grep lit une entrée, commence à la traiter.
  • À un certain point, grepproduit un premier morceau de sortie.
  • head lit ce premier morceau et l'écrit.
  • En supposant qu'il y a suffisamment de lignes après les 10 premiers matchs (sinon cela greppourrait se terminer en premier), headle nombre de lignes souhaité sera éventuellement imprimé. À ce stade, headquitte.
  • Selon la vitesse relative des processus grepet head, il est greppossible que certaines données aient été accumulées et ne les aient pas encore imprimées. Au moment de la headsortie, greppeut lire une entrée ou effectuer un traitement interne, auquel cas il continuera de le faire.
  • Bientôt grep, les données seront traitées. À ce stade, il recevra un SIGPIPE et mourra.

Il est probable que grepcela traitera un peu plus d'entrée que strictement nécessaire, mais généralement seulement quelques kilo-octets:

  • headlit généralement en morceaux de quelques kilo-octets (car c'est plus efficace que d'émettre un readappel système pour chaque octet - ce comportement est appelé mise en mémoire tampon), donc le reste du dernier morceau après la dernière ligne souhaitée est rejeté.
  • Il peut y avoir des données en transit, car les tuyaux ont un tampon associé géré par le noyau (souvent 512 octets). Ces données seront supprimées.
  • greppeut avoir accumulé des données prêtes à devenir un bloc de sortie (mise en mémoire tampon à nouveau). Il recevra SIGPIPE lorsqu'il essaiera de vider son tampon de sortie.

Dans l'ensemble, le système est précisément conçu pour que les utilitaires de filtrage se comportent naturellement de manière efficace. Les programmes qui doivent continuer lorsque leur canal de sortie s'éteint doivent prendre la décision d'ignorer le signal SIGPIPE.

Gilles 'SO- arrête d'être méchant'
la source
3

Sortof, le pipeline fonctionne comme ceci: il exécute d'abord la première commande puis la deuxième commande dans votre cas.

Autrement dit, soyons A|Bla commande donnée. Ensuite, il n'est pas certain que Aou Bcommence en premier. Ils peuvent démarrer exactement au même moment s'il y a plusieurs processeurs. Un canal peut contenir une quantité indéfinie mais limitée de données.

Si B essaie de lire à partir du canal, mais qu'aucune donnée n'est disponible, Battendra que les données arrivent. Si Blisait à partir d'un disque, Bpeut avoir le même problème et doit attendre la fin d'une lecture sur disque. Une analogie plus étroite serait la lecture à partir d'un clavier. Là, Bil faudrait attendre qu'un utilisateur tape. Mais dans tous ces cas, B a commencé une opération de «lecture» et doit attendre sa fin. Mais si Best une commande telle qu'elle n'a besoin que d'une sortie partielle, Aalors après un certain point où le Bniveau d'entrée est atteint A, SIGPIPE sera tué

Si Aessaie d'écrire sur le tuyau et que le tuyau est plein, vous Adevez attendre qu'une certaine place dans le tuyau soit libérée. Apourrait avoir le même problème s'il écrivait sur un terminal. Un terminal dispose d'un contrôle de flux et peut modérer le rythme des données. Dans tous les cas, to A, il a démarré une opération "d'écriture" et attendra la fin de l'opération d'écriture.

Aet Bse comportent comme des co-processus, bien que tous les co-processus ne communiquent pas avec un tuyau. Aucun des deux n'a le plein contrôle de l'autre.

harish.venkat
la source
1
La question est: "que ferait A lorsque B ferme son côté du tuyau?"
enzotib
2
Ce ne serait pas un «tuyau cassé»?
Patkos Csaba
1
Si un programme essaie de lire / écrire depuis / vers un canal fermé (par exemple, headquitte), un signal SIGPIPE se produit dans le programme et le comportement par défaut est de quitter.
Lekensteyn
Comment cela répond-il exactement à la question? Il semble que la réponse de psusi soit plus courte et plus pertinente .
jw013 du
1

grepn'a aucun contrôle direct sur le tuyau (il ne fait que recevoir des données), et le tuyau n'a aucun contrôle direct sur grep(il envoie simplement des données) ...

Ce que fait grep, ou tout autre programme, dépend entièrement de la logique interne de ce programme. Si vous dites grepvia les options de ligne de commande de faire une sortie anticipée une fois trouvé , alors il le fera, sinon il se connectera à la toute fin du fichier à la recherche du modèle ...

Le Terminal est également assez déconnecté du fonctionnement interne grepet shelldes actions de tuyauterie du ... Le Terminal est fondamentalement juste une rampe de lancement et un affichage de sortie ...

Peter.O
la source