File pseudo per dati temporanei


98

Spesso desidero inviare dati stringa relativamente brevi (che potrebbero essere diverse righe) a programmi a riga di comando che accettano ripetutamente l'input dai file (ad es. Wdiff). Certo che posso creare uno o più file temporanei, salvare lì la stringa ed eseguire il comando con il nome del file come parametro. Ma mi sembra che questa procedura sarebbe altamente inefficiente se i dati vengono effettivamente scritti sul disco e potrebbe anche danneggiare il disco più del necessario se ripeto questa procedura molte volte, ad esempio se voglio alimentare singole righe di testo lungo file su wdiff. Esiste un modo consigliato per aggirare questo, ad esempio usando file pseudo come pipe per archiviare temporaneamente i dati senza effettivamente scriverli sul disco (o scriverli solo se supera una lunghezza critica). Nota che wdiff accetta due argomenti e,wdiff <"text".


Questo può essere risolto tramite xargs?
NN,

Non lo so, ma non sarebbe ovvio per me come. A quanto ho capito xargs, renderebbe le righe di input dagli argomenti della stringa di file per il comando. Ma ho bisogno del contrario.
highsciguy

@rahmu Ho dato un'occhiata, ma penso che l'impostazione del problema sia un po 'diversa lì. Almeno non vedo come le risposte potrebbero aiutare. La risposta accettata per produrre correttamente i file temporanei è essenzialmente ciò che non voglio evitare, se non c'è un qualche tipo di buffering che impedisce effettivamente di scrivere i file. Ho una conoscenza limitata di come funzionano i file temporanei!
highsciguy

Cosa c'è che non va echo $data_are_here | dumb_program?
vonbrand,

1
Ciò supporterebbe un solo file di input e non tutti i programmi leggessero da stdin.
highsciguy,

Risposte:


55

Usa una pipa denominata . A titolo illustrativo:

mkfifo fifo
echo -e "hello world\nnext line\nline 3" > fifo

L' -eeco dice di interpretare correttamente la newline escape ( \n). Questo bloccherà, cioè la shell si bloccherà fino a quando qualcosa non legge i dati dalla pipe.

Apri un'altra shell da qualche parte e nella stessa directory:

cat fifo

Leggerai l'eco, che rilascerà l'altra shell. Sebbene la pipe esista come nodo del file sul disco, i dati che la attraversano no; tutto si svolge nella memoria. È possibile eseguire lo sfondo ( &) dell'eco.

La pipe ha un buffer 64k (su Linux) e, come un socket, bloccherà lo scrittore quando è pieno, quindi non perderai dati finché non ucciderai prematuramente lo scrittore.


Ok, grazie, funziona anche con due named pipe e wdiff. Ma ho pensato di capire che esiste una certa (piccola) memoria disponibile per la pipe come buffer. Cosa succede se supero la dimensione del buffer?
highsciguy,

Ho aggiunto un paragrafo finale su tale questione.
Riccioli d'oro,

3
/tmpè configurato nella maggior parte delle distribuzioni per usare un tmpfsfilesystem che si trova nella RAM. Quando scrivi un file, /tmpquesto va direttamente nella tua RAM, il che rende una buona risposta per i file semi-resilienti a cui è necessario accedere rapidamente e riscritti molte volte.

129

In Bash, è possibile utilizzare la command1 <( command0 )sintassi di reindirizzamento, che reindirizza lo command0stdout e lo passa a un command1che accetta un nome file come argomento della riga di comando. Questo si chiama sostituzione del processo .

Alcuni programmi che accettano argomenti da riga di comando in nome file necessitano effettivamente di un vero file ad accesso casuale, quindi questa tecnica non funzionerà per quelli. Tuttavia, funziona bene con wdiff:

user@host:/path$ wdiff <( echo hello; echo hello1 ) <( echo hello; echo hello2 )
hello
[-hello1-]
{+hello2+}

Sullo sfondo, questo crea un FIFO, reindirizza il comando all'interno <( )del FIFO e passa il descrittore di file FIFO come argomento. Per vedere cosa sta succedendo, prova a usarlo con echoper stampare l'argomento senza farci nulla:

user@host:/path$ echo <( echo hello )
/dev/fd/63

La creazione di una pipe denominata è più flessibile (se si desidera scrivere una logica di reindirizzamento complicata utilizzando più processi), ma per molti scopi è sufficiente ed è ovviamente più facile da usare.

C'è anche la >( )sintassi per quando vuoi usarla come output, ad es

$ someprogram --logfile >( gzip > out.log.gz )

Vedi anche il foglio informativo sui reindirizzamenti di Bash per le tecniche correlate.


Questo non è supportato in KSH
chanchal1987,

5
ksh ha inventato questo. Stai usando una variante di ksh che non lo supporta
Neil McGuigan,

2
Alcuni programmi che accettano argomenti da riga di comando in nome file necessitano effettivamente di un vero file ad accesso casuale, quindi questa tecnica non funzionerà per quelli. Cosa fai in questi casi. Ad esempio ssh -F <(vagrant ssh-config) defaultsarebbe davvero bello ma purtroppo.
Sukima,

10

wdiff è un caso speciale in quanto richiede 2 argomenti per i nomi dei file, ma per tutti i comandi che richiedono solo 1 argomento e che ostinatamente si rifiutano di accettare qualsiasi cosa tranne un argomento per i nomi di file, ci sono 2 opzioni:

  • Il nome del file '-' (ovvero un segno meno) funziona circa la metà delle volte. Sembra dipendere dal comando in questione e se lo sviluppatore del comando intrappola quel caso e lo gestisce come previsto. per esempio

    $> ls | gatto -

  • Esiste un file psuedo chiamato / dev / stdin che esiste in Linux e può essere usato se un comando richiede assolutamente un nome file. È più probabile che funzioni perché non richiede alcuna gestione speciale del nome file dal comando. Se un FIFO funziona o il metodo di sostituzione del processo bash funziona, anche questo dovrebbe funzionare e non è specifico della shell. per esempio

    $> ls | cat / dev / stdin


1
less e openssl come / dev / stdin anziché / dev / fd / NUM :-)
eel ghEEz
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.