2012-02-21 13 views
22

Ho problemi a convogliare lo stdin a uno script R.Piping stdin to R

Ecco il mio script giocattolo test.R:

#!/usr/bin/env Rscript 
while(length(line <- readLines('stdin', n=1, warn=FALSE)) > 0) { 
    write(line, stderr()) 
    # process line 
} 

mi piacerebbe passare attraverso ogni linea e fare un po 'di elaborazione. Ecco il mio file di input nome input:

aaaaaa 
bbbbbb 
cccccc 
dddddd 
eeeeee 
ffffff 

Se faccio

cat input | test.R 

io ho soltanto:

aaaaaa 

C'è qualcosa che ho perso?

risposta

37

Ciò non accade se si apre esplicitamente la connessione stdin.

#!/usr/bin/env Rscript 
f <- file("stdin") 
open(f) 
while(length(line <- readLines(f,n=1)) > 0) { 
    write(line, stderr()) 
    # process line 
} 
+0

Grande. Questo funziona. Grazie. – WYi

+2

Abbiamo bisogno di chiudere il file alla fine? –

+1

Se vuoi che R faccia la cosa più tipica di "unix-y" e attendi input da stdin (quindi il codice nella risposta si comporterebbe in modo simile all'esecuzione di 'cat' senza argomenti) allora devi usare' open (f , blocking = TRUE) '. – dshepherd

11

Jeff e io abbiamo scritto littler per fare solo questo (e alcune altre cose). A causa di littler, non ho mai guardato da vicino a Rscript - ma questo dovrebbe in linea di principio funziona bene.

Qui è uno dei nostri primi esempi, utilizzando l'uscita da /bin/ls (e un rapido filtro awk) per riassumere la dimensione del file:

[email protected]:~/svn/littler/examples$ ls -l /boot/ | \ 
            awk '!/^total/ {print $5}' | ./fsizes.r 
    Min. 1st Qu. Median  Mean 3rd Qu.  Max. 
     24 130300 730700 3336000 4527000 14670000 

    The decimal point is 6 digit(s) to the right of the | 

    0 | 0000000000000011111111122777777777 
    2 | 777777777 
    4 | 555577777 
    6 | 
    8 | 
    10 | 
    12 | 5 
    14 | 24466677 

[email protected]:~/svn/littler/examples$ 

Ecco lo script fsizes.r è a soli tre linee:

[email protected]:~/svn/littler/examples$ cat fsizes.r 
#!/usr/bin/r -i 

fsizes <- as.integer(readLines()) 
print(summary(fsizes)) 
stem(fsizes) 
[email protected]:~/svn/littler/examples$ 
+0

readlines() legge tutte le linee in memoria, che è quello che sto cercando di evitare. Spero di leggere riga per riga, con n = 1 in readLines() – WYi

+0

Quindi metti un filtro awk/sed/grep/... nella pipe, o dump su file e seleziona. R vuole davvero che tutti i suoi input fossero letti. –

1

Questo è il più semplice che ho found (supponendo input numerico):

x <- scan(file="stdin", quiet=TRUE) 

potete provarlo con:

$ echo -e "1\n2\n3" | R --slave -e 'x <- scan(file="stdin", quiet=TRUE); summary(x)' 
    Min. 1st Qu. Median Mean 3rd Qu. Max. 
    1.0  1.5  2.0  2.0  2.5  3.0