11

I wrote a small R script to read JSON, which works fine but upon piping with

Rscript myscript.R | head

the (full, expected) output comes back with an error

Error: ignoring SIGPIPE signal
Execution halted

Oddly I can't remove this by piping STDERR to /dev/null using:

Rscript myscript.R | head 2>/dev/null

The same error is given... presumably because the error arises within the Rscript command? The suggestion to me is that the output of the head command is all STDOUT.

  • Piping STDOUT to /dev/null returns only the error message
  • Piping STDERR to /dev/null returns only the error message...!

Piping the output to cat seems to be 'invisible' - this doesn't cause an error.

Rscript myscript.R | cat | head

Further pipe chaining is possible after the cat command but it feels like I may be ignoring something important by not addressing the error.

Is there a setting I need to use within the script to permit piping without the error? I'd like to have R scripts at the ready for small tasks as is done with the likes of Python and Perl, and it'd get annoying to always have to add a useless cat.

There is discussion of handling this error in C here, but it's not immediately clear to me how this would relate to an R script.

Edit In response to @lll's answer, the full script in use (above called as 'myscript.R') is

library(RJSONIO)
note.list <- c('abcdefg.json','hijklmn.json')
# unique IDs for markdown notes stored in JSON by Laverna, http://laverna.cc
for (laverna.note in note.list) {
  # note.file <- path.expand(file.path('~/Dropbox/Apps/Laverna/notes',
  #                                   laverna.note))
  # For the purpose of this example run the script in the same
  # directory as the JSON files
  note.file <- path.expand(file.path(getwd(),laverna.note))
  file.conn <- file(note.file)
  suppressWarnings( # warnings re: no terminating newline
    cat(paste0(substr(readLines(file.conn), 2, 15)),'\n') # add said newline
  )
  close(file.conn)
}

Rscript myscript.R outputs

"id":"abcdefg"
"id":"hijklmn" 

Rscript myscript.R | head -1 outputs

"id":"abcdefg" 
Error: ignoring SIGPIPE signal
Execution halted

It's not clear to me what would be terminating 'early' here

Edit 2 It's replicable with readLines so I've removed JSON library-specific details in the example above. Script and dummy JSON gisted here.

Edit 3 It seems it may be possible to take command-line arguments including pipes and pass them to pipe() - I'll try this when I can and resolve the question.

Community
  • 1
  • 1
Louis Maddox
  • 5,226
  • 5
  • 36
  • 66

3 Answers3

5

The error is simply caused by an attempt to write to the pipe without a process connected to the other end. In other words, your script has already picked up and left by the time the pipe is reached and the HEAD command is called.

The command itself might not be the issue; it could be something within the script causing an early termination or race condition before reaching the pipe. Since you're getting full output it may not be that much of a concern, however, masking the error with other CLI commands as mentioned probably isn't the best approach.


The command line solution:

R does have a couple of useful commands for dealing with instances in which you might want the interpreter to wait, or perhaps suppress any errors that would normally be output to stderr.

For command-line R, error messages written to ‘stderr’ will be sent to the terminal unless ignore.stderr = TRUE. They can be captured (in the most likely shells) by:

system("some command 2>&1", intern = TRUE)

There is also the wait argument which could help with keeping the process alive.

wait — logical (not NA) indicating whether the R interpreter should wait for the command to finish, or run it asynchronously. This will be ignored (and the interpreter will always wait) if intern = TRUE.

 system("Rscript myscript.R | head 2>&1", intern = TRUE)

The above would wait, and output errors, if any are thrown.

system("Rscript myscript.R | head", intern = FALSE, ignore.stderr = TRUE)

The above won't wait, but would suppress errors, if any.

Louis Maddox
  • 5,226
  • 5
  • 36
  • 66
l'L'l
  • 44,951
  • 10
  • 95
  • 146
  • Thanks, I've updated my question. I can't see any prematurely-terminating process though. Could you edit your answer to explain 'terminating' (unless it's brief enough for a comment)? The script is a for loop over 2 elements, which are both processed in the output I see, so I don't understand what premature stage this could be. – Louis Maddox Mar 07 '15 at 15:04
  • It might be the `close(file.conn)` perhaps where things get terminated too quickly. Sometimes this type of behavior is also known also as a [race condition](https://www.google.com/search?q=race+condition&ie=utf-8&oe=utf-8). Try commenting out the `close(file.conn)` for a moment and then run the command and see if you encounter the same issue. – l'L'l Mar 07 '15 at 15:26
  • The point is though that I want a script that can be chained to new commands at will. I could take the pipe as an argument within the `system()` call as `system(paste0("Rscript myscript.R | ",args), intern=TRUE)`... but... to pass a pipe in as arguments seems wrong? It would only work for one command (using an actual `|` would end argument reading) so how is a system call able to accept and chain piped output? – Louis Maddox Mar 07 '15 at 19:09
  • Personally I have no problem using most any standard unix commands within `system`, but it really boils down to what your needs are and how you want to do it. There is a specific front-end you may be interested in called [littler](https://github.com/eddelbuettel/littler), which is described as: "a simplified command-line interface for GNU R. This allows direct execution of commands, use in piping where the output of one program supplies the input of the next..." - ([more info](http://dirk.eddelbuettel.com/code/littler.html)) – l'L'l Mar 07 '15 at 19:25
  • 1
    The docs often seem to illustrate the use of `system`, so maybe they're onto something. I did a quick peek to see if there might be any similar issues to yours and noticed [one in particular that stood out](http://stackoverflow.com/a/9534215/499581). – l'L'l Mar 07 '15 at 19:43
2

I encountered the same annoying error. It appears to be generated from within R by a function writing to STDOUT, if the R function is still running (outputting data to the pipe) when the pipe stops 'listening'.

So, errors can be suppressed by simply wrapping the R output function into try(...,silent=TRUE), or specifically this error can be handled by wrapping the R output function into a more-involved tryCatch(...,error=...) function.

Example: Here's a script that generates an error when piped:

#! /Library/Frameworks/R.framework/Resources/bin/rscript
random_matrix=matrix(rnorm(2000),1000)
write.table(x=random_matrix,file="",sep=",",row.names=FALSE,col.names=FALSE)

Output when called from bash and piped to head:

./myScript.r | head -n 1
-1.69669866833626,-0.463199773124574
Error in write.table(x = random_matrix, file = "", sep = ",", row.names = FALSE,  :
  ignoring SIGPIPE signal
Execution halted

So: wrap the write.table output function into try to suppress all errors that occur during output:

try(write.table(x=random_matrix,file="",sep=",",row.names=FALSE,col.names=FALSE),silent=TRUE)

Or, more-specific, just suppress the "ignoring SIGPIPE signal" error:

tryCatch(write.table(x=random_matrix,file="",sep=",",row.names=FALSE,col.names=FALSE),
    error=function(e) if(!grepl("ignoring SIGPIPE signal",e$message))stop(e) )
1

I could overcome this problem by using littler instead of Rscript:

r myscript.R | head
Farid Cheraghi
  • 847
  • 2
  • 12
  • 23