[R] writing R shell scripts?

Henrik Bengtsson hb at maths.lth.se
Wed Nov 9 06:45:28 CET 2005


Mike Miller wrote:

>On Wed, 9 Nov 2005, Henrik Bengtsson wrote:
>
>  
>
>>What you really want to do might be solved by write.table(), e.g.
>>
>>x <- matrix(rnorm(25*2),c(25,2));
>>write.table(file=stdout(), x, row.names=FALSE, col.names=FALSE);
>>    
>>
>
>Thanks.  That does what I want.
>
>There is one remaining problem for my "echo" method.  While write.table 
>seems to do the right thing for me, R seems to add an extra newline to the 
>output when it closes.  You can see that this produces exactly one newline 
>and nothing else:
>
># echo '' | R --slave --no-save | wc -c
>       1
>
>Is there any way to stop R from sending an extra newline?  It's funny 
>because normal running of R doesn't seem to terminate by sending a newline 
>to stdout.  Oops -- I just figured it out.  If I send "quit()", there is 
>no extra newline!  Examples that send no extra newline:
>
>echo 'quit()' | R --slave --no-save
>
>echo "x <- matrix(rnorm(25*2),c(25,2)); write.table(file=stdout(), x, row.names=FALSE, col.names=FALSE); quit()" | R --slave --no-save
>
>I suppose we can live with that as it is.  Is this an intentional feature?
>
>
>  
>
>>A note of concern: When writing batch scripts like this, be explicit and 
>>use the print() statement.  A counter example to compare
>>
>>echo "1; 2" | R --slave --no-save
>>
>>and
>>
>>echo "print(1); print(2)" | R --slave --no-save
>>    
>>
>
>I guess you are saying that sometimes R will fail if I don't use print(). 
>Can you give an example of how it can fail?
>  
>
What I was really try to say is that if you running the R terminal, that 
is, you "sending" commands via the R prompt, R will take the *last* 
value and call print()  on it.  This is why you get the result when you type

 > 1+1
[1] 2

Without this "feature" you would have had to type
 > print(1+1)
[1] 2

to get any results.  Note that it is only the last value calculate, that 
will be output this way, cf.
 > 1+1; 2+2
[1] 4

In other words, in the latter example '1+1' is pretty useless and does 
nothing but taking up CPU time.  So, whenever you write batch scripts 
like yours or standard R scripts called by source(), do use print() 
explicitly (or cat() or write.table() or ...) if want output!

>>>By the way, I find it useful to have a script in my path that does 
>>>this:
>>>
>>>#!/bin/sh
>>>echo "$1" | /usr/local/bin/R --slave --no-save
>>>
>>>Suppose that script was called "doR", then one could do things like 
>>>this from the Linux/UNIX command line:
>>>
>>># doR 'sqrt(35.6)'
>>>[1] 5.966574
>>>
>>># doR 'runif(1)'
>>>[1] 0.8881654
>>>
>>>Which I find to be handy for quick arithmetic and even for much more 
>>>sophisticated things.  I'd like to get rid of the "[1]" though!
>>>      
>>>
>>If you want to be lazy and not use, say, doR 'cat(runif(1),"\n")' above, 
>>maybe a simple Unix sed in your shell script can fix that?!
>>    
>>
>
>
>It looks like I can rewrite the script like this:
>
>#!/bin/sh
>echo "$1 ; write.table(file=stdout(), out, row.names=FALSE, col.names=FALSE); quit()" | /usr/local/bin/R --slave --no-save
>
>Then I have to always include something like this...
>
>out <- some_operation
>
>...as part of my command.  Example:
>
>  
>
Or go get the last value calculated by .Last.value, see

echo "$1; out <- .Last.value; write.table(file=stdout(), out, row.names=FALSE, col.names=FALSE); quit()" | /usr/local/bin/R --slave --no-save

You may also want to create your own method for returning/outputting 
data.  An ideal way for doing this is to use create a so called generic 
function, say, returnOutput(), and then special functions for each class 
of object that you might get returned, e.g. returnOutput.matrix(), 
returnOutput.list(), etc. Don't forget returnOutput.default().  If you 
do not understand what I'm talking about here, please read up on 
S3/UseMethod in R documentation.  It's all in there.  Then you'll also 
get a much deeper understanding of how print() (and R) works.  Please 
don't ask me to explain it on the mailing list.

Cheers

Henrik

># doR 'A <- matrix(rnorm(100*5),c(100,5)); out <- chol(cov(A))'
>1.08824564637869 0.00749462665482204 -0.109577665309141 0.123824503621501 0.0420504647142321
>0 0.969304154505745 0.0689085053799411 0.143273894584171 -0.0204348333174425
>0 0 0.995383836907855 0.0860782051613422 0.056980680914183
>0 0 0 0.94180592438191 0.0534651651371964
>0 0 0 0 0.907266109886987
>
>Now we've got it!!
>
>The output above is nice and compact, and it doesn't have an extra 
>newline, but if you want it to look nice on the screen, my friend Stephen 
>Montgomery-Smith (Math, U Missouri) made me this nice little perl script 
>for aligning numbers neatly and easily (but it doesn't work if there are 
>letters in there (e.g., NA or 1.3e-6):
>
>http://taxa.epi.umn.edu/misc/numalign
>
># ./doR 'A <- matrix(rnorm(100*5),c(100,5)); out <- chol(cov(A))' | numalign
>0.903339952680364 -0.088773840144205 -0.223677935069773  -0.0736286093726908  0.0457396703130186
>0                  1.08096548052082   0.0800540640587432 -0.0457840266135511 -0.0311210293661459
>0                  0                  0.93834307353671    0.0665017259723313 -0.0825698771035788
>0                  0                  0                   1.03303581434252    0.118372967026342
>0                  0                  0                   0                   0.972768611955302
>
>Thanks very much for all of the help!!!
>
>Mike
>
>  
>




More information about the R-help mailing list