Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to find correct executable with Sys.which on Windows

Tags:

windows

r

What are the workarounds on Windows to make it so Sys.which finds the proper executables? Two cases that are reoccuring problems:

  1. convert.exe which is both a windows program and the ImageMagik program, but Sys.which only finds the windows one which is never wanted from R no matter how I seem to arrange things on my PATH.

  2. tar.exe is packaged along with various things like git or mingw or whatever, and even when I have Rtools and Rbuildtools first in my path, the tar program from Rtools is never found, for example when installing a package from source.

So, I have resorted to writing a wrapper that calls 7-zip instead whenever I am on windows. This can't be the thing to do can it?

Edit

Actually just adding an environment variable to .Renviron: TAR=path/to/tar.exe works fine for the install.packages example, and I am having trouble remembering where else the tar.exe was biting me, but Josh answered the main one, convert.exe.

like image 310
Rorschach Avatar asked Dec 01 '15 21:12

Rorschach


People also ask

How can you know the path of an executable file command?

PATH without parameters will display the current path. The %PATH% environment variable contains a list of folders. When a command is issued at the CMD prompt, the operating system will first look for an executable file in the current folder, if not found it will scan %PATH% to find it.

How do I find the path of a command in Windows?

Windows 10 Alternatively follow the instructions below to open the command prompt (even faster than on Windows Server). Go to the destination folder and click on the path (highlights in blue). type cmd. Command prompt opens with the path set to your current folder.

How do I find the path of a program?

To find the installation folder of a program using a desktop shortcut: From your desktop, right-click on the program's shortcut. Click on the Properties, and the Properties window should now be displayed. Click on the Shortcut tab, and you will find the installation path in the Target field.

What is executable path?

The full pathname of the receiver's executable file.


2 Answers

I asked a +/- identical question earlier this year over on R-devel. Among the replies was this one, by Henrik Bengtsson, who kindly provided the following useful function:

Sys.which2 <- function(cmd) {
    stopifnot(length(cmd) == 1)
    if (.Platform$OS.type == "windows") {
        suppressWarnings({
            pathname <- shell(sprintf("where %s 2> NUL", cmd), intern=TRUE)[1]
        })
        if (!is.na(pathname)) return(setNames(pathname, cmd))
    }
    Sys.which(cmd)
}

## Trying out Sys.which & Sys.which2 on my Windows box gives the following:
Sys.which("convert")
#                              convert 
# "C:\\Windows\\system32\\convert.exe" 
Sys.which2("convert")
#                                                 convert 
# "C:\\Program Files\\ImageMagick-6.8.8-Q16\\convert.exe" 

I'm really not sure why R-core don't just fix Sys.which() to make it actually portable, but they at least do document root cause of this behavior in ?system (whose functionality is afflicted by the same problem):

The search path for 'command' may be system-dependent: it will include the R 'bin' directory, the working directory and the Windows system directories before 'PATH'.

like image 76
Josh O'Brien Avatar answered Oct 16 '22 05:10

Josh O'Brien


Because Sys.which() is vectorized–and since I think that is useful–I've modified the Henrik Bengtsson code in the following function sys_which(), which should be a more robust and more similar version of Sys.which():

## check if unix
is_unix <- function() grepl("unix", .Platform$OS.type, ignore.case = TRUE)

## robust version of Sys.which
sys_which <- function(x) {
  if (is_unix()) {
    return(Sys.which(x))
  }
  sys_win <- function(x) {
    if (grepl("\\S", path <- Sys.which(x))) {
      return(path)
    }
    path <- tryCatch(
      suppressWarnings(system(sprintf("where %s", x), intern = TRUE)[1]),
      warning = function(w) "",
      error = function(e) "")
    if (!grepl("\\S", path)) {
      return(`names<-`("", x))
    }
    `names<-`(path, x)
  }
  vapply(x, sys_win, character(1))
}

This has the following advantages:

  1. It's vectorizedsys_which() can handle a vector (one or more input values) e.g., sys_which(c("python", "python3"))
  2. It's more error resistant–use of tryCatch(...) ensures any inputs that result in an error from the system call get passed on to the normal Sys.which() function.

Example:

> sys_which(c("python", "python2.7", "python3", "asdf"))
#>            python                python2.7                  python3        asdf 
#> "/usr/bin/python"     "/usr/bin/python2.7" "/usr/local/bin/python3"          ""
like image 45
mkearney Avatar answered Oct 16 '22 06:10

mkearney