Bash Pipe Handling


29

Qualcuno sa come bash gestisce l'invio di dati tramite pipe?

cat file.txt | tail -20 

Questo comando stampa tutto il contenuto di file.txt in un buffer, che viene quindi letto dalla coda? Oppure questo comando, ad esempio, stampa il contenuto di file.txt riga per riga, quindi si interrompe su ciascuna riga affinché tail to process e quindi richieda più dati?

La ragione per cui chiedo è che sto scrivendo un programma su un dispositivo incorporato che fondamentalmente esegue una sequenza di operazioni su alcuni blocchi di dati, in cui l'uscita di un'operazione viene inviata come input dell'operazione successiva. Mi piacerebbe sapere come gestisce Linux (bash), quindi per favore forniscimi una risposta generale, non specificamente cosa succede quando eseguo "cat file.txt | tail -20".

Grazie in anticipo per le vostre risposte!

EDIT: Shog9 ha indicato un articolo di Wikipedia pertinente, questo non mi ha portato direttamente all'articolo ma mi ha aiutato a trovare questo: http://en.wikipedia.org/wiki/Pipeline_%28Unix%29#Implementation che aveva le informazioni che stavo cercando.


Mi dispiace per non essere stato chiaro. Ovviamente stai usando una pipe e ovviamente stai usando stdin e stdout delle rispettive parti del comando. Avevo pensato che fosse troppo ovvio per affermare.

Quello che sto chiedendo è come questo viene gestito/implementato. Poiché entrambi i programmi non possono essere eseguiti contemporaneamente, come vengono inviati i dati da stdin a stdout? Cosa succede se il primo programma genera dati significativamente più veloci del secondo programma? Il sistema esegue solo il primo comando fino a quando non viene terminato o il buffer stdout è pieno, quindi passa al programma successivo e così via in un ciclo finché non vengono lasciati più dati da elaborare o esiste un meccanismo più complicato ?

54

Ho deciso di scrivere una spiegazione leggermente più dettagliata.

La "magia" si trova nel sistema operativo. Entrambi i programmi si avviano all'incirca alla stessa ora e vengono eseguiti contemporaneamente (il sistema operativo assegna loro una porzione di tempo sul processore da eseguire) come ogni altro processo in esecuzione simultaneamente sul computer (compresa l'applicazione terminale e il kernel) . Quindi, prima che i dati vengano superati, i processi stanno facendo tutto ciò che è necessario per l'inizializzazione. Nel tuo esempio, tail sta analizzando l'argomento '-20' e cat sta analizzando l'argomento 'file.txt' e aprendo il file. Ad un certo punto, coda arriverà al punto in cui ha bisogno di input e dirà al sistema operativo che è in attesa di input. In qualche altro punto (prima o dopo, non importa) cat inizierà a passare i dati al sistema operativo usando stdout. Questo va in un buffer nel sistema operativo. La prossima volta che tail acquisisce una porzione di tempo sul processore dopo che alcuni dati sono stati inseriti nel buffer da cat, recupererà una certa quantità di quei dati (o tutti) che lasciano il buffer nel sistema operativo. Quando il buffer è vuoto, ad un certo punto tail dovrà aspettare che il gatto produca più dati. Se il gatto sta trasmettendo i dati molto più velocemente di quanto sta gestendo la coda, il buffer si espanderà.Alla fine, cat farà uscire i dati, ma tail sarà ancora in fase di elaborazione, quindi cat si chiuderà e tail processerà tutti i restanti dati nel buffer. Il sistema operativo segnalerà coda quando non ci sono più dati in arrivo con un EOF. Tail elaborerà i dati rimanenti. In questo caso, coda sta probabilmente ricevendo tutti i dati in un buffer circolare di 20 righe, e quando viene segnalato dal sistema operativo che non ci sono più dati in arrivo, quindi scarica le ultime venti righe nel proprio stdout, che viene semplicemente visualizzato nel terminale. Poiché tail è un programma molto più semplice di cat, probabilmente trascorrerà la maggior parte del tempo in attesa che il gatto inserisca i dati nel buffer.

Su un sistema con più processori, i due programmi non condivideranno solo intervalli di tempo alternati sullo stesso core del processore, ma probabilmente funzioneranno contemporaneamente su core separati.

Per ottenere maggiori dettagli, se si apre una sorta di monitor di processo (specifico del sistema operativo) come "top" in Linux, verrà visualizzato un intero elenco di processi in esecuzione, la maggior parte dei quali utilizza efficacemente lo 0% di il processore. La maggior parte delle applicazioni, a meno che non stiano trucidando i dati, trascorrono la maggior parte del tempo a non fare nulla. Ciò è positivo, perché consente ad altri processi di avere accesso senza restrizioni al processore in base alle loro esigenze. Questo si ottiene in tre modi. Un processo potrebbe arrivare ad un'istruzione di tipo sleep (n) dove dice sostanzialmente al kernel di aspettare n millisecondi prima di dargli un'altra porzione di tempo con cui lavorare. Più comunemente un programma deve attendere qualcosa da un altro programma, come "coda" in attesa che altri dati entrino nel buffer. In questo caso, il sistema operativo riattiverà il processo quando saranno disponibili più dati. Infine, il kernel può prevenire un processo nel mezzo dell'esecuzione, assegnando alcune fette di tempo del processore ad altri processi. 'gatto' e 'coda' sono programmi semplici. In questo esempio, tail trascorre la maggior parte del tempo in attesa di altri dati sul buffer e cat passa la maggior parte del tempo in attesa che il sistema operativo recuperi i dati dall'hard disk. Il collo di bottiglia è la velocità (o la lentezza) del supporto fisico su cui è archiviato il file. Il ritardo percepibile che è possibile rilevare quando si esegue questo comando per la prima volta è il tempo richiesto dalle testine di lettura sul disco rigido per cercare la posizione sull'hard disk in cui è "file.txt". Se si esegue il comando una seconda volta, il sistema operativo avrà probabilmente il contenuto di file.txt memorizzato nella cache e non sarà possibile vedere alcun ritardo percettibile (a meno che file.txt non sia molto grande o il file non sia più memorizzato nella cache .)

La maggior parte delle operazioni eseguite sul computer sono legate all'IO, vale a dire che di solito si attende l'arrivo di dati dal disco rigido o da un dispositivo di rete, ecc.


0

cat stamperà semplicemente i dati sullo standard out, che risulta essere reindirizzati allo standard in coda. Questo può essere visto nella pagina man di bash.

In altre parole, non c'è alcuna pausa in corso, la coda è solo la lettura dallo standard in e cat sta semplicemente scrivendo per standard.


1

Shog9 ha già fatto riferimento all'articolo di Wikipedia, ma lo implementation section ha i dettagli desiderati. L'implementazione di base è un buffer limitato.