2010-11-03 12 views
6

Ho un programma di utilità da una terza parte (è grande e scritto in Java) che ho usato per aiutarmi a elaborare alcuni dati. Questa utility si aspetta le informazioni in un file delimitato da una linea e quindi invia i dati elaborati a STDOUT.C'è un modo per fornire stdin/out invece di un file in un programma in unix?

Durante le fasi di test, stavo bene scrivendo un po 'di Perl per creare un file pieno di informazioni da elaborare e quindi inviare quel file a questa utility di terze parti, ma mentre mi avvicino alla messa in produzione di questo codice, Preferisco davvero solo inviare i dati a questa utility direttamente anziché scrivere prima quei dati in un file, in quanto ciò mi salverà dal sovraccarico di dover scrivere informazioni non necessarie sul disco. C'è un modo per farlo in Unix?

Attualmente mi chiamano l'utilità come segue:

bin/someapp do-action --option1 some_value --input some_file

mi piacerebbe fare qualcosa di simile:

bin/someapp do-action --option1 some_value --input $piped_in_data

È qualcosa di simile possibile senza la mia modificare la terza parte app?

+0

C'è una risposta molto più completa su StackExchange, vedere . – weynhamz

risposta

10

Si dovrebbe essere in grado di utilizzare/dev/stdin:

bin/someapp do-action --option1 some_value --input /dev/stdin 

(Si noti che su alcuni sistemi,/dev/stdin è un link simbolico; se il programma Java non far fronte a questo, si potrebbe utilizzare invece/dev/fd/0 o qualcosa di simile)

+0

Quindi a che punto dovrei inviare i dati allo stdin allora? Lo aspetteresti dopo averlo chiamato? O dovrei farlo immediatamente prima mano? Come funzionerebbe esattamente? – Eli

+0

Usalo in una pipeline normale: 'generate_data.pl | bin/someapp do-action --option1 some_value --input/dev/stdin' –

+0

Impressionante. Questo è proprio quello che volevo. – Eli

10

È possibile utilizzare "sostituzione di processo" in bash per ottenere qualcosa di simile a ciò che si desidera.

bin/someapp do-action --option1 some_value --input <(generate_input.sh) 

dovrebbe fare il trucco. La parte <(list) è la sostituzione del processo.

+0

Dolce! c'è un modo per usare uno script perl lì? Per provare, ho provato: echo <(perl -e 'print "yo;"'), ma non sembra funzionare. – Eli

+0

provate invece: cat - <<(perl -le 'print "yo"') :) – pavel

+0

O semplicemente 'cat <(perl qualunque cosa)'. Il bit <(...) viene sostituito con il nome di un file che rappresenta una pipe per i dati generati. 'echo' non sa leggere dai file, ma' cat' lo fa. –

2

Un altro percorso, se la tecnica /dev/stdin non è adatta per qualche motivo, è utilizzare una "named pipe".

Se fai

% mkfifo /path/to/file 

allora questo creerà un oggetto file system con quel nome, che può agire come un condotto tra due processi. Questo è lo stesso di quello che succede con una pipe normale, con la differenza che i processi possono riferirsi alla pipe come se fosse un normale file. Per esempio:

% mkfifo /tmp/my-fifo 
% grep alias ~/.bashrc >/tmp/my-fifo & 
[1] 70134 
% sed 's/alias/wibble/' /tmp/my-fifo 
wibble ls='ls -F' 
.... 
[1] + done  grep alias ~/.bashrc > /tmp/my-fifo 
% 

Qui, il comando grep sta scrivendo il FIFO esattamente come se fosse un file normale, e blocchi quando il buffer del named pipe si riempie. Il processo sed legge dalla pipe (come se fosse un normale file), svuotando il buffer mentre lo fa.

2

Non è così facile./dev/stdin, named pipe e la sostituzione del processo <() non sono accessibili da un programma allo stesso modo di un file. In particolare non è possibile fseek(), fsetpos() all'interno di tale costrutto, perché la sua lunghezza non è nota a priori.

Alcune funzioni come fopen(), getc(), fread() ecc. Funzioneranno comunque. Pertanto, per la maggior parte dei programmi che leggono semplicemente l'inserimento riga per riga o carattere per carattere, ciò avverrà.

Se il programma cerca all'interno di un file (e forse fa altre operazioni "più avanzate"), è necessario creare un file temporaneo, sfortunatamente.

Problemi correlati