Pipa con nome buffer non bloccante?


20

Sto cercando qualcosa che sospetto non esista: una pipe di nome buffer (non bloccata) non bloccabile da utilizzare dalla riga di comando. C'è una cosa del genere?

Ecco il caso d'uso: supponiamo che io abbia un processo che durerà a lungo in background e spargerà molto output stdout. Non mi interessa davvero l'output e non voglio memorizzarlo (forse non ho abbastanza spazio per), ma mi piacerebbe "entrare" periodicamente e seguire ciò che sta facendo, quindi abbandonare di nuovo e lasciarlo fare il suo lavoro. Quindi mi piacerebbe reindirizzare il suo output a questa teorica pipe bufferizzata, non bloccante, e poi attingere periodicamente.

Quindi in pratica voglio iniziare in questo modo ( 10Messendo la dimensione del buffer):

mkmagicfifo magicfifo 10M
spewingprocess > magicfifo &

... e periodicamente entrare per vedere cosa sta succedendo ...

tail -f magicfifo

... senza magicfifo archiviare tutto l'output (quindi, non un file normale), e senza che blocchi il processo di sputa quando si riempie e non viene toccato (quindi, non è un normale pipe chiamato).

Non penso che le soluzioni coinvolgano tailo prunelo faranno (beh, posso pensare a una soluzione alternativa che coinvolga tail), perché tailrichiederei comunque di archiviare tutti i dati da qualche parte (se voglio entrare e uscire dal guardarli), e prunedeve riscrivere il file, presumibilmente (ammetto di non aver provato / provato questo) interrompendo il reindirizzamento del processo generando tutto l'output.

Mi aspetto di poter scrivere qualche utilità per farlo, ma * nix ha così tanti aspetti interessanti di file e pipe e simili, non posso fare a meno di pensare che questo esista e semplicemente non lo so.

Quindi: esiste una cosa del genere, e in caso affermativo che cos'è?


1
Quello che stai descrivendo è un "buffer ad anello" o "buffer circolare". Non sono a conoscenza di strumenti della riga di comando per mantenere una cosa del genere, anche se sarebbe banale da creare.
— Shawn J. Goff,

2
Dai un'occhiata alle soluzioni descritte in "Linux non bloccante fifo (registrazione su richiesta)", stackoverflow.com/questions/7360473/… .

1
Sembra che questo sia stato risolto su StackOverflow: stackoverflow.com/questions/7360473/…
— James Blackburn,

@JamesBlackburn: grazie! Molto interessante.
— TJ Crowder,

Risposte:


16

Penso che quello che stai cercando sia GNU screen. Mantiene un buffer per mantenere l'ultimo schermo pieno o due di output da uno o più programmi e consente di disconnettersi e tornare più tardi.


+1 per suggerire schermo. A proposito, è possibile configurarlo per contenere molte "righe della cronologia".
— Shunz,

1
Grazie. Puoi fare un esempio di come lo applicheresti ai comandi che ho mostrato nella mia domanda? La pagina man dice che è un gestore di finestre (penso che significhino in senso terminale, non in senso grafico, ma comunque). E sarei ancora in grado di entrare (tramite ssh) e abbandonare se necessario? (Ad esempio, operazioni su server remoti.)
— TJ Crowder,

Sì, puoi usare lo schermo GNU in questo modo. Dovresti creare una nuova sessione (potenzialmente denominata), eseguire il comando all'interno di quella sessione e quindi disconnetterti.
— TML,

2
C'è anche tmuxe dtach- qualsiasi cosa nella stessa classe di applicazione terminal multiplexer / session manager dovrebbe essere in grado di ottenere la stessa cosa.
— jw013,

5

È possibile utilizzare pv, fornisce tutto il buffering che si desidera in una pipeline. Puoi usarlo in questo modo:

sprewingprocess | pv -B 1g > ordinaryfifo &

Ciò ti darebbe fino a 1 GB di buffering tra spewingprocesse il fifo. La maggior parte delle distribuzioni Linux offrono pvin un pacchetto chiamato, che ci crediate o no pv,.


Grazie, ma non si bloccherebbe una volta che il buffer era pieno se non stavo leggendo il target chiamato pipe?
— TJ Crowder,

1
Sì, ma che scelta hai? In un universo finito, non puoi avere un buffering letteralmente illimitato.
— David Schwartz,

L'altra scelta è come ho descritto nella mia domanda: non memorizzare tutto l'output. Quando il buffer è pieno, le cose più vecchie vengono eliminate.
— TJ Crowder,

Hmm, l'ho provato e sfortunatamente non funziona del tutto. Se il processo di lettura del fifo interrompe la lettura per un po ', pv blocca il tentativo di scrivere nel fifo e, poiché non è multithread, blocca anche la lettura dei dati nel buffer di pv. Quindi il buffer di pv continuerà a riempirsi solo mentre il processo di lettura del fifo continua a leggere. pv potrebbe essere in grado di leggere e bufferizzare alcuni dati, ma ciò non impedisce al writer di bloccarsi completamente.
— Daniel S. Sterling,

1

Ho avuto lo stesso problema. Questa è la mia prima soluzione. Prima scrivi l'output in un file che tronciamo dopo ogni riga in modo che non cresca indefinitamente:

spewingprocess | while read line; do echo $line > buffer.txt ; done

Quindi leggi dal file usando tail (dove 2> /dev/nullelimina il messaggio di errore "file troncato"):

tail -f ./buffer.txt 2> /dev/null

In questo modo il buffer non cresce e possiamo multiplexare, ad esempio eseguire tutte le code che vogliamo. Tuttavia, il problema con questo approccio è che possiamo perdere dati quando tronciamo più velocemente di quanto coda possa leggere come mostra questo test:

for ((i=0; ; i++)) ; do echo "$i" ; done | while read line; do  echo $line > buffer.txt ; done
tail -f ./buffer.txt 2> /dev/null > log.txt

Dopo aver eseguito per qualche tempo la prima e l'ultima riga sono:

$ head -n 1 log.txt
0
$ tail -n 1 log.txt
78783

Ma il file ha meno righe, quindi alcune vanno perse:

$ wc log.txt
67087  67087 392819 log.txt

Tuttavia, questa sembra una buona soluzione se non ti preoccupi così tanto della perdita di dati o quando il tuo processo di sputa non è abbastanza veloce per la perdita di dati.

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.