[R] system() and file names with spaces

Richard A. O'Keefe ok at cs.otago.ac.nz
Fri Dec 10 03:15:11 CET 2004


Brian D Ripley <ripley at stats.ox.ac.uk> wrote:
	The normal way to do this is to quote the string, here filename.  See
	?shQuote.
	
	Your comments really are not fair:

My comments were to the effect that *I* had recommended an approach
that didn't quite work.  There's nothing unfair to R or the R team in that.

I tried to do something helpful about it.
My next comment was:

	> If there's already something like for.system() built into R, I'd be very
	> happy to know about it.

I don't see anything unfair about that either.  It's a clear suggestion
that I expected that there _was_ something like for.system() built into R.
What's unfair about hinting that I expect the problem is already solved?
I didn't say that R didn't *have* a solution, just that *I* didn't know about
it.

In retrospect, that WAS unfair.  It was unfair to me.
Because you see, I did go looking.

THERE IS NOTHING ABOUT shQuote in ?system or ?pipe.  Not in the text,
not in the examples, and not in the See Also section.

	> (It's a little odd that system() and pipe()
	> don't already support something like this;

This is the one and only comment which could in any way be taken as critical
of R or the R team.  I stand by my comment that

	> in a multi-element character
	> vector the first could be taken literally and the remaining ones could be
	> taken quoted with leading spaces.)

This would be

    old.system <- system
    system <- function (command, intern = FALSE, ignore.stderr = FALSE) {
	if (length(command > 1))
	    command <- do.call("paste", c(command[1],
                               lapply(com[2:length(command)], shQuote)))
	old.system(command, intern, ignore.stderr)
    }

or, more directly,

    system <- function (command, intern = FALSE, ignore.stderr = FALSE) {
	if (length(command > 1))
	    command <- do.call("paste", c(command[1],
			       lapply(com[2:length(command)], shQuote)))
	.Internal(system(if (ignore.stderr) paste(command, "2>/dev/null")
			 else command, intern))
    }

This would mean that something like
    system(c("mv", old.name, new.name))
would work _without_ the user having to remember to call shQuote.

This leads me to pipe().   In ?pipe we read

description: character. A description of the connection. For 'file' and
          'pipe' this is a path to the file to be opened. For 'url' it
          is a complete URL, including schemes ('http://', 'ftp://' or
          'file://').  'file' also accepts complete URLs. 

This should be

description: character. A description of the connection. For 'file' this
	  is a path to the file to be opened.  For 'pipe' it is the OS
	  command which is to be run.  For 'url' it is a complete URL,
          including schemes ('http://', 'ftp://' or 'file://').
	  'file' also accepts complete URLs. 


The 'See Also' section of ?pipe should include a paragraph:

	For 'pipe', see 'system' and 'shQuote'.

In the help page for 'system' the paragraph

     If 'intern' is 'FALSE' then the C function 'system' is used to
     invoke the command and the value returned by 'system' is the exit
     status of this function.

should be followed by a new paragraph:

     While your operating system may allow almost any string as a file
     name, the system command interpreter doesn't.  Some characters,
     such as spaces, quotation marks, and apostrophes, are likely to
     give you trouble.  You should only paste file names into a command
     directly when you are certain that they do not contain any unusual
     characters.  If they are valid R identifiers, you should have no
     trouble.  In general, you should quote file names using shQuote(),
     which knows what needs quoting for your system command interpreter
     and how to do that quoting.

Then in See Also:

     'shQuote' for quoting file names as and when necessary.

Then in Examples:

     file.name <- "What's On"
     quoted.name <- shQuote(file.name)
     system(paste("echo nothing >", quoted.name))
     system(paste("ls -l", quoted.name))
     system(paste("rm", quoted.name))

(This example has been tested.)

Had something like this already been in those help files, I would have
found shQuote when I went looking for it.




More information about the R-help mailing list