Qual è la differenza tra "Reindirizzamento" e "Pipe"?


205

Questa domanda può sembrare un po 'stupida, ma non riesco davvero a vedere la differenza tra reindirizzamento e pipe.

Il reindirizzamento viene utilizzato per reindirizzare lo stdout / stdin / stderr, ad es ls > log.txt.

I tubi vengono utilizzati per fornire l'output di un comando come input per un altro comando, ad es ls | grep file.txt.

Ma perché ci sono due operatori per la stessa cosa?

Perché non scrivere solo ls > grepper trasmettere l'output, non è anche solo una sorta di reindirizzamento? Cosa mi manca

Risposte:


224

Pipe viene utilizzato per passare l'output a un altro programma o utilità .

Il reindirizzamento viene utilizzato per passare l'output a un file o flusso .

Esempio: thing1 > thing2vsthing1 | thing2

thing1 > thing2

  1. La shell eseguirà il programma denominato thing1
  2. Tutto ciò che thing1output verrà inserito in un file chiamato thing2. (Nota: se thing2esiste, verrà sovrascritto)

Se si desidera passare l'output dal programma thing1a un programma chiamato thing2, è possibile effettuare le seguenti operazioni:

thing1 > temp_file && thing2 < temp_file

quale sarebbe

  1. eseguire il programma denominato thing1
  2. salva l'output in un file denominato temp_file
  3. eseguire il programma denominato thing2, fingendo che la persona alla tastiera abbia digitato il contenuto temp_filecome input.

Tuttavia, questo è ingombrante, quindi hanno creato i tubi come un modo più semplice per farlo. thing1 | thing2fa la stessa cosa dithing1 > temp_file && thing2 < temp_file

MODIFICA per fornire maggiori dettagli da porre in commento:

Se si >tenta di essere sia "passa al programma" che "scrivi su file", potrebbe causare problemi in entrambe le direzioni.

Primo esempio: stai provando a scrivere su un file. Esiste già un file con quel nome che desideri sovrascrivere. Tuttavia, il file è eseguibile. Presumibilmente, proverebbe a eseguire questo file, passando l'input. Dovresti fare qualcosa come scrivere l'output con un nuovo nome file, quindi rinominare il file.

Secondo esempio: come ha sottolineato Florian Diesch, cosa succede se c'è un altro comando nel sistema con lo stesso nome (che si trova nel percorso di esecuzione). Se intendevi creare un file con quel nome nella cartella corrente, rimarrai bloccato.

Terzo: se si digita male un comando, non ti avvertirebbe che il comando non esiste. In questo momento, se lo digiti te ls | gerp log.txtlo dirà bash: gerp: command not found. Se >significasse entrambi, creerebbe semplicemente un nuovo file per te (quindi avvisa che non sa cosa fare log.txt).


Grazie. Hai detto thing1 > temp_file && thing2 < temp_filedi fare di più con le pipe. Ma perché non riutilizzare l' >operatore per farlo, ad esempio thing1 > thing2per i comandi thing1e thing2? Perché un operatore extra |?
John Threepwood,

1
"Prendi l'output e scrivilo in un file" è un'azione diversa da "Prendi l'output e passalo a un altro programma". Modificherò altri pensieri nella mia risposta ...
David Oneill,

1
@JohnThreepwood Hanno significati diversi. E se volessi reindirizzare qualcosa su un file chiamato less, ad esempio? thing | lesse thing > lesssono perfettamente diversi, poiché fanno cose diverse. Ciò che proponi creerebbe un'ambiguità.
Darkhogg,

È corretto affermare che "thing1> temp_file" è semplicemente zucchero sintattico per "thing1 | tee temp_file"? Da quando ho scoperto il tee non uso quasi mai i reindirizzamenti.
Sridhar Sarnobat,

2
@ Sridhar-Sarnobat no, il teecomando fa qualcosa di diverso. teescrive l'output sia sullo schermo ( stdout) che sul file. Il reindirizzamento esegue solo il file.
David Oneill,

22

Se il significato di foo > bardipende dal fatto che esista un comando chiamato barche renderebbe il reindirizzamento molto più difficile e più soggetto a errori: ogni volta che voglio reindirizzare a un file, devo prima verificare se esiste un comando chiamato come il mio file di destinazione.


Questo sarebbe un problema solo se stai scrivendo barin una directory che fa parte della tua $PATHvariabile env. Se ti trovi in ​​qualcosa come / bin, allora ot potrebbe essere un problema. Ma anche in questo caso, bardovrebbe essere impostato un permesso eseguibile, in modo che la shell controlli non solo per trovare un eseguibile, barma in realtà può eseguirlo. E se il problema riguarda la sovrascrittura dei file esistenti, l' nocloberopzione shell dovrebbe impedire la sovrascrittura dei file esistenti nei reindirizzamenti.
Sergiy Kolodyazhnyy,

13

Dal manuale di amministrazione del sistema Unix e Linux:

reindirizzamento

La shell interpreta i simboli <,> e >> come istruzioni per reindirizzare l' input o l'output di un comando verso o da un file .

Pipes

Per connettere lo STDOUT di un comando allo STDIN di un altro usa il | simbolo, comunemente noto come pipa.

Quindi la mia interpretazione è: se è il comando da comandare, usa una pipe. Se stai eseguendo l'output da o verso un file, utilizza il reindirizzamento.


12

C'è una differenza vitale tra i due operatori:

  1. ls > log.txt -> Questo comando invia l'output al file log.txt.

  2. ls | grep file.txt-> Questo comando invia l'output del comando ls a grep tramite l'uso di pipe ( |) e il comando grep cerca file.txt nell'input fornito dal comando precedente.

Se dovessi eseguire la stessa attività utilizzando il primo scenario, sarebbe:

ls > log.txt; grep 'file.txt' log.txt

Quindi una pipe (con |) viene utilizzata per inviare l'output ad altri comandi, mentre il reindirizzamento (con >) viene utilizzato per reindirizzare l'output su un file.


3

C'è una grande differenza sintattica tra i due:

  1. Un reindirizzamento è un argomento per un programma
  2. Una pipe separa due comandi

Si può pensare di reindirizzamenti come questo: cat [<infile] [>outfile]. Ciò implica che l'ordine non ha importanza: cat <infile >outfileè uguale a cat >outfile <infile. Puoi anche mescolare i reindirizzamenti con altri argomenti: cat >outfile <infile -be cat <infile -b >outfilestanno entrambi perfettamente bene. Inoltre è possibile stringa insieme più di un ingresso o di uscita (ingressi verranno letti in sequenza e tutto l'output verrà scritto ogni file di output): cat >outfile1 >outfile2 <infile1 <infile2. La destinazione o l'origine di un reindirizzamento può essere un nome file o il nome di uno stream (come & 1, almeno in bash).

Ma le pipe separano totalmente un comando da un altro comando, non puoi mescolarli con argomenti:

[command1] | [command2]

La pipe prende tutto ciò che è scritto nello standard output da command1 e lo invia allo standard input di command2.

Puoi anche combinare piping e reindirizzamento. Per esempio:

cat <infile >outfile | cat <infile2 >outfile2

Il primo catleggerà le righe dall'infile, quindi scriverà simultaneamente ogni riga nel file di output e lo invierà al secondo cat.

Nel secondo cat, l'input standard prima legge dalla pipe (il contenuto dell'infile), quindi legge da infile2, scrivendo ogni riga in outfile2. Dopo aver eseguito ciò, outfile sarà una copia di infile e outfile2 conterrà infile seguito da infile2.

Infine, fai effettivamente qualcosa di molto simile al tuo esempio usando il reindirizzamento "here string" (solo famiglia bash) e i backtick:

grep blah <<<`ls`

darà lo stesso risultato di

ls | grep blah

Ma penso che la versione di reindirizzamento leggerà prima tutto l'output di ls in un buffer (in memoria), quindi alimenterà quel buffer per grep una riga alla volta, mentre la versione con piping prenderà ogni riga da ls mentre emerge, e passa quella linea a grep.


1
Nitpick: ordina le cose nel reindirizzamento se reindirizzi un fd a un altro: echo yes 1>&2 2>/tmp/blah; wc -l /tmp/blah; echo yes 2>/tmp/blah 1>&2; wc -l /tmp/blahInoltre, il reindirizzamento a un file utilizzerà solo l'ultimo reindirizzamento. echo yes >/tmp/blah >/tmp/blah2scriverò solo a /tmp/blah2.
muru,

2
Il reindirizzamento non è in realtà argomento per il programma. Il programma non saprà né si preoccuperà di dove va (o arriva l'input). È solo un modo per dire a bash come organizzare le cose prima di eseguire il programma.
Alois Mahdal,

3

Nota: la risposta riflette la mia comprensione di questi meccanismi aggiornati, accumulati durante la ricerca e la lettura delle risposte dai peer su questo sito e unix.stackexchange.com , e verranno aggiornati con il passare del tempo. Non esitate a porre domande o suggerire miglioramenti nei commenti. Ti suggerisco anche di provare a vedere come funzionano syscalls in shell con stracecomando. Inoltre, non fatevi intimidire dalla nozione di interni o syscalls - non dovete conoscerli o essere in grado di usarli per capire come shell fa le cose, ma sicuramente aiutano a capire.

TL; DR

  • |le pipe non sono associate a una voce sul disco, quindi non hanno un numero di inode del filesystem del disco (ma hanno inode nel filesystem virtuale pipefs nello spazio del kernel), ma i reindirizzamenti spesso coinvolgono file, che hanno voci del disco e quindi hanno corrispondenti inode.
  • le pipe non sono in lseek()grado, quindi i comandi non possono leggere alcuni dati e quindi riavvolgere indietro, ma quando si reindirizza con >o di <solito si tratta di un file che è lseek()oggetto in grado, quindi i comandi possono navigare come preferiscono.
  • i reindirizzamenti sono manipolazioni sui descrittori di file, che possono essere molti; le pipe hanno solo due descrittori di file: uno per il comando a sinistra e uno per il comando a destra
  • il reindirizzamento su stream e pipe standard è entrambi bufferato.
  • i tubi coinvolgono quasi sempre il biforcazione e quindi sono coinvolte coppie di processi; reindirizzamenti - non sempre, sebbene in entrambi i casi i descrittori di file risultanti siano ereditati da sottoprocessi.
  • le pipe collegano sempre descrittori di file (una coppia), reindirizzamenti - utilizzare un nome percorso o descrittori di file.
  • le pipe sono il metodo di comunicazione tra processi, mentre i reindirizzamenti sono solo manipolazioni su file aperti o oggetti simili a file
  • entrambi utilizzano dup2()syscalls sotto il cofano per fornire copie dei descrittori di file, in cui si verifica il flusso effettivo di dati.
  • i reindirizzamenti possono essere applicati "a livello globale" con il execcomando integrato (vedi questo e questo ), quindi se lo fai exec > output.txttutti i comandi scriveranno output.txtda quel momento in poi. |le pipe vengono applicate solo per il comando corrente (che significa comando semplice o subshell seq 5 | (head -n1; head -n2)o comandi composti.
  • Quando il reindirizzamento viene eseguito sui file, cose come echo "TEST" > fileed echo "TEST" >> fileentrambi usano open()syscall su quel file ( vedi anche ) e ottengono da esso il descrittore di file per passarlo dup2(). Pipes |use only pipe()e dup2()syscall.

  • Per quanto riguarda i comandi in esecuzione, pipe e reindirizzamento non sono altro che descrittori di file - oggetti simili a file, su cui possono scrivere alla cieca o manipolarli internamente (il che può produrre comportamenti imprevisti; aptad esempio, tende a non scrivere nemmeno su stdout se sa che c'è il reindirizzamento).

introduzione

Per capire in che modo differiscono questi due meccanismi, è necessario comprendere le loro proprietà essenziali, la storia dietro i due e le loro radici nel linguaggio di programmazione C. In realtà, sapere quali file di descrittori sono, e come dup2()e pipe()sistema di chiamate di lavoro è essenziale, così come lseek(). Shell è inteso come un modo per rendere astratti questi meccanismi per l'utente, ma scavare più a fondo dell'astrazione aiuta a comprendere la vera natura del comportamento della shell.

Le origini di reindirizzamenti e tubi

Secondo l'articolo di Dennis Ritche Prophetic Petroglyphs , le pipe sono nate da una nota interna del 1964 di Malcolm Douglas McIlroy , all'epoca in cui stavano lavorando al sistema operativo Multics . Citazione:

Per riassumere le mie più forti preoccupazioni:

  1. Dovremmo avere alcuni modi per collegare programmi come il tubo da giardino: avvitare un altro segmento quando diventa quando diventa necessario massaggiare i dati in un altro modo. Questo è anche il modo di IO.

Ciò che è evidente è che all'epoca i programmi erano in grado di scrivere su disco, tuttavia ciò era inefficiente se l'output era grande. Per citare la spiegazione di Brian Kernighan nel video di Unix Pipeline :

Innanzitutto, non devi scrivere un grosso programma di grandi dimensioni: hai programmi più piccoli esistenti che potrebbero già fare parte del lavoro ... Un altro è che è possibile che la quantità di dati che stai processando non si adatterebbe se l'hai archiviato in un file ... perché ricorda, siamo tornati nei giorni in cui i dischi su queste cose avevano, se sei stato fortunato, un Megabyte o due di dati ... Quindi la pipeline non ha mai dovuto istanziare l'intero output .

Quindi la differenza concettuale è evidente: le pipe sono un meccanismo per far dialogare i programmi. Reindirizzamenti: sono un modo di scrivere su file a livello base. In entrambi i casi, shell rende queste due cose facili, ma sotto il cofano c'è molto da fare.

Approfondimento: syscalls e meccanismi interni della shell

Iniziamo con la nozione di descrittore di file . I descrittori di file descrivono sostanzialmente un file aperto (che si tratti di un file su disco o in memoria o di un file anonimo), che è rappresentato da un numero intero. I due flussi di dati standard (stdin, stdout, stderr) sono rispettivamente descrittori di file 0,1 e 2. Da dove vengono ? Bene, nei comandi di shell i descrittori di file sono ereditati dalla loro shell madre. Ed è vero in generale per tutti i processi: il processo figlio eredita i descrittori di file dei genitori. Per i demoni è comune chiudere tutti i descrittori di file ereditati e / o reindirizzare verso altri luoghi.

Torna al reindirizzamento. Che cos'è veramente? È un meccanismo che dice alla shell di preparare i descrittori di file per il comando (perché i reindirizzamenti vengono effettuati dalla shell prima dell'esecuzione del comando) e li indirizzano dove l'utente ha suggerito. La definizione standard di reindirizzamento dell'output è

[n]>word

Che [n]esiste il numero del descrittore di file. Quando lo fai echo "Something" > /dev/nullil numero 1 è implicito lì, e echo 2> /dev/null.

Sotto il cofano questo viene fatto duplicando il descrittore di file tramite la dup2()chiamata di sistema. Prendiamo df > /dev/null. La shell creerà un processo figlio dove dfviene eseguita, ma prima si aprirà /dev/nullcome descrittore di file n. 3 e dup2(3,1)verrà emessa, il che crea una copia del descrittore di file 3 e la copia sarà 1. Sai come hai due file file1.txte file2.txte quando lo fai cp file1.txt file2.txtavrai due stessi file, ma puoi manipolarli in modo indipendente? È un po 'la stessa cosa che succede qui. Spesso puoi vedere che prima di eseguirlo, lo bashfarà dup(1,10)per creare un descrittore di file di copia n. 1 che è stdout(e quella copia sarà fd # 10) per ripristinarlo in seguito. È importante notare che quando si considerano i comandi integrati(che fanno parte della shell stessa e non hanno file all'interno /bino altrove) o semplici comandi nella shell non interattiva , la shell non crea un processo figlio.

E poi abbiamo cose come [n]>&[m]e [n]&<[m]. Si tratta di duplicare i descrittori di file, che lo stesso meccanismo come dup2()solo ora è nella sintassi della shell, comodamente disponibili per l'utente.

Una delle cose importanti da notare sul reindirizzamento è che il loro ordine non è fisso, ma è significativo per il modo in cui la shell interpreta ciò che l'utente desidera. Confronta quanto segue:

# Make copy of where fd 2 points , then redirect fd 2
$ ls -l /proc/self/fd/  3>&2  2> /dev/null
total 0
lrwx------ 1 user user 64 Sep 13 00:08 0 -> /dev/pts/0
lrwx------ 1 user user 64 Sep 13 00:08 1 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:08 2 -> /dev/null
lrwx------ 1 runner user 64 Sep 13 00:08 3 -> /dev/pts/0
lr-x------ 1 user user 64 Sep 13 00:08 4 -> /proc/29/fd

# redirect fd #2 first, then clone it
$ ls -l /proc/self/fd/    2> /dev/null 3>&2
total 0
lrwx------ 1 user user 64 Sep 13 00:08 0 -> /dev/pts/0
lrwx------ 1 user user 64 Sep 13 00:08 1 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:08 2 -> /dev/null
l-wx------ 1 user user 64 Sep 13 00:08 3 -> /dev/null
lr-x------ 1 user user 64 Sep 13 00:08 4 -> /proc/31/fd

L'uso pratico di questi negli script di shell può essere versatile:

e molti altri.

Impianto idraulico con pipe()edup2()

Come si creano le pipe? Tramite pipe()syscall , che prenderà come input un array (aka list) chiamato pipefddi due elementi di tipo int(intero). Quei due numeri interi sono descrittori di file. Il pipefd[0]sarà la fine lettura della pipe e pipefd[1]sarà la fine scrittura. Quindi df | grep 'foo', grepotterrà una copia pipefd[0]e dfriceverà una copia di pipefd[1]. Ma come ? Certo, con la magia di dup2()Syscall. Per dfesempio, nel nostro esempio, diciamo che pipefd[1]ha il numero 4, quindi la shell farà un figlio, fallo dup2(4,1)(ricordi il mio cpesempio?), E poi execve()eseguirà effettivamente df. Naturalmente,dferediterà il descrittore di file n. 1, ma non si accorgerà che non punta più al terminale, ma in realtà fd n. 4, che in realtà è l'estremità di scrittura della pipe. Naturalmente, accadrà la stessa cosa se grep 'foo'non con un numero diverso di descrittori di file.

Ora, domanda interessante: potremmo creare pipe che reindirizzino anche fd # 2, non solo fd # 1? Sì, in effetti è quello che |&fa in bash. Lo standard POSIX richiede il linguaggio dei comandi della shell per supportare la df 2>&1 | grep 'foo'sintassi a tale scopo, ma lo bashfa |&anche.

La cosa importante da notare è che le pipe si occupano sempre dei descrittori di file. Esiste FIFOo denominato pipe , che ha un nome file sul disco e ti consente di usarlo come file, ma si comporta come una pipe. Ma i |tipi di pipe sono noti come pipe anonime: non hanno un nome file, perché sono in realtà solo due oggetti collegati tra loro. Il fatto che non abbiamo a che fare con i file comporta anche un'importante implicazione: le pipe non sono lseek()'in grado. I file, sia in memoria che su disco, sono statici: i programmi possono usare lseek()syscall per saltare al byte 120, quindi tornare al byte 10, quindi inoltrare fino alla fine. I tubi non sono statici: sono sequenziali e pertanto non è possibile riavvolgere i dati ottenuti con essilseek(). Questo è ciò che rende consapevoli alcuni programmi se stanno leggendo da file o da pipe, e quindi possono apportare le necessarie regolazioni per prestazioni efficienti; in altre parole, progposso rilevare se lo faccio cat file.txt | progo prog < input.txt. Il vero esempio di lavoro è la coda .

Le altre due proprietà molto interessanti delle pipe sono che hanno un buffer, che su Linux è di 4096 byte , e in realtà hanno un filesystem come definito nel codice sorgente di Linux ! Non sono semplicemente un oggetto per il trasferimento di dati, ma sono una struttura di dati! Infatti, poiché esiste un filesystem pipefs, che gestisce sia pipe sia FIFO, le pipe hanno un numero di inode sul rispettivo filesystem:

# Stdout of ls is wired to pipe
$ ls -l /proc/self/fd/  | cat  
lrwx------ 1 user user 64 Sep 13 00:02 0 -> /dev/pts/0
l-wx------ 1 user user 64 Sep 13 00:02 1 -> pipe:[15655630]
lrwx------ 1 user user 64 Sep 13 00:02 2 -> /dev/pts/0
lr-x------ 1 user user 64 Sep 13 00:02 3 -> /proc/22/fd
# stdin of ls is wired to pipe
$ true | ls -l /proc/self/fd/0
lr-x------ 1 user user 64 Sep 13 03:58 /proc/self/fd/0 -> 'pipe:[54741]'

Su Linux le pipe sono unidirezionali, proprio come il reindirizzamento. Su alcune implementazioni simili a Unix - ci sono tubi bidirezionali. Sebbene con la magia degli script di shell, puoi creare pipe bidirezionali anche su Linux .

Guarda anche:


2

Per aggiungere alle altre risposte, ci sono anche sottili differenze semantiche - ad esempio, le pipe si chiudono più rapidamente dei reindirizzamenti:

seq 5 | (head -n1; head -n1)                # just 1
seq 5 > tmp5; (head -n1; head -n1) < tmp5   # 1 and 2
seq 5 | (read LINE; echo $LINE; head -n1)   # 1 and 2

Nel primo esempio, quando headtermina la prima chiamata , chiude la pipe e seqtermina, quindi non c'è input disponibile per la seconda head.

Nel secondo esempio, head consuma la prima riga, ma quando chiude la propria stdin pipe , il file rimane aperto per essere utilizzato dalla chiamata successiva.

Il terzo esempio mostra che se usiamo readper evitare di chiudere il tubo è ancora disponibile all'interno del sottoprocesso.

Quindi lo "stream" è la cosa attraverso cui spostiamo i dati (stdin ecc.), Ed è lo stesso in entrambi i casi, ma la pipe collega i flussi da due processi, in cui un reindirizzamento collega i flussi tra un processo e un file, quindi tu può vedere la fonte di entrambe le somiglianze e le differenze.

PS Se sei curioso e / o sorpreso da quegli esempi come me, puoi approfondire ulteriormente usando trapper vedere come si risolvono i processi, ad esempio:

(trap 'echo seq EXITed >&2' EXIT; seq 5) | (trap 'echo all done' EXIT; (trap 'echo first head exited' EXIT; head -n1)
echo '.'
(trap 'echo second head exited' EXIT; head -n1))

A volte il primo processo si chiude prima che 1venga stampato, a volte in seguito.

Ho anche trovato interessante usare exec <&-per chiudere il flusso dal reindirizzamento per approssimare il comportamento della pipe (anche se con un errore):

seq 5 > tmp5
(trap 'echo all done' EXIT
(trap 'echo first head exited' EXIT; head -n1)
echo '.'
exec <&-
(trap 'echo second head exited' EXIT; head -n1)) < tmp5`

"quando termina la prima chiamata a head, chiude la pipe" Questo è in realtà inaccurato per due motivi. Uno, (head -n1; head -n1) è subshell con due comandi, ognuno dei quali eredita la fine di lettura del pipe come descrittore 0, e quindi subshell E ogni comando ha quel descrittore di file aperto. Secondo motivo, puoi vederlo con strace -f bash -c 'seq 5 | (head -n1; head -n1) '. Quindi la prima testa chiude solo la sua copia del descrittore di file
Sergiy Kolodyazhnyy,

Anche il terzo esempio è impreciso, poiché readconsuma solo la prima riga (ovvero un byte per 1e newline). seqinviato in totale 10 byte (5 numeri e 5 nuove righe). Quindi rimangono 8 byte nel buffer delle pipe, ed è per questo che il secondo headfunziona - ci sono ancora dati disponibili nel buffer delle pipe. A proposito, la testa esce solo se ci sono 0 byte letti, un po 'come inhead /dev/null
Sergiy Kolodyazhnyy,

Grazie per il chiarimento. Sto capendo correttamente che nella seq 5 | (head -n1; head -n1)prima chiamata svuota la pipe, quindi esiste ancora in uno stato aperto ma senza dati per la seconda chiamata head? Quindi la differenza di comportamento tra la pipe e il reindirizzamento è perché head estrae tutti i dati dalla pipe, ma solo le 2 righe dall'handle del file?
Julian de Bhal,

È corretto. Ed è qualcosa che può essere visto con il stracecomando che ho dato nel primo commento. Con il reindirizzamento, il file tmp è su disco che lo rende ricercabile (perché usano lseek()syscall - i comandi possono saltare il file dal primo byte all'ultimo come vogliono. Ma i tubi sono sequenziali e non ricercabili. Quindi l'unico modo per head di fare il suo il lavoro è leggere prima tutto, o se il file è grande - mappare parte di esso su RAM tramite mmap()chiamata. Una volta ho fatto il mio tailsu Python e
ho riscontrato

È anche importante ricordare che la fine della lettura della pipe (descrittore di file) viene prima assegnata a subshell (...)e la subshell eseguirà la copia del proprio stdin su ciascun comando all'interno (...). Quindi sono tecnicamente letti dallo stesso oggetto. Innanzitutto head pensa che stia leggendo dal proprio stdin. Secondo headpensa che abbia il suo stdin. Ma in realtà il loro fd # 1 (stdin) è solo una copia dello stesso fd, che viene letto alla fine della pipe. Inoltre, ho pubblicato una risposta, quindi forse aiuterà a chiarire le cose.
Sergiy Kolodyazhnyy,

1

Oggi ho riscontrato un problema con questo in C. In sostanza, Pipe ha anche una semantica diversa da reindirizzare, anche quando viene inviato stdin. Credo davvero che, date le differenze, le pipe dovrebbero andare in un posto diverso da quello stdin, in modo che stdine chiamiamolo stdpipe(per fare un differenziale arbitrario) possa essere gestito in diversi modi.

Considera questo. Quando si reindirizza l'output di un programma a un altro, fstatsembra restituire zero come st_sizenonostante sia ls -lha /proc/{PID}/fddimostrato che esiste un file. Quando si reindirizza un file, non è così (almeno su debian wheezy, stretche jessievanilla e ubuntu 14.04, 16.04vanilla.

Se hai cat /proc/{PID}/fd/0un reindirizzamento, sarai in grado di ripetere per leggere tutte le volte che vuoi. Se lo fai con una pipe noterai che la seconda volta che esegui l'attività consecutivamente, non otterrai lo stesso output.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.