Creating a soft symbolic link from R on Windows - r

I'd like to create a soft symbolic link to a file from within R on Windows (with Mklink). It fails because I cannot tell R to "run it as administrator". Is there any way I can do this?
I did manage to create hard symbolic file links, however:
path_src <- file.path(tempdir(), "test.txt")
write("Hello World!", file = path_src)
path_tgt <- file.path(tempdir(), "test_symlink.txt")
shell(sprintf("mklink /H %s %s",
normalizePath(path_tgt, mustWork = FALSE),
normalizePath(path_src)
))
Note how the file at path_tgt reflects the changes made to path_src:
write("HELLO WORLD!", file = path_src, append = TRUE)
Yet, this fails:
path_tgt_2 <- file.path(tempdir(), "test_symlink_2.txt")
> shell(sprintf("mklink /D %s %s",
normalizePath(path_tgt_2, mustWork = FALSE),
normalizePath(path_src)
))
Ihre Berechtigungen reichen nicht aus, um diesen Vorgang auszufhren.
Warning messages:
1: running command 'C:\Windows\system32\cmd.exe /c mklink /D C:\Users\Thyson\AppData\Local\Temp\Rtmpum73ZU\test_symlink_2.txt C:\Users\Thyson\AppData\Local\Temp\Rtmpum73ZU\test.txt' had status 1
2: In shell(sprintf("mklink /D %s %s", normalizePath(path_tgt_2, mustWork = FALSE), :
'mklink /D C:\Users\Thyson\AppData\Local\Temp\Rtmpum73ZU\test_symlink_2.txt C:\Users\Thyson\AppData\Local\Temp\Rtmpum73ZU\test.txt' Ausführung mit Fehlerkode 1 fehlgeschlagen
Note
Due to a German version of Windows I can't seem to get the errors in English. The first line translates to somewhat along the lines of "You don't have enough authorization in order to carry out this process"

Run R as administrator. Then when you run "Mklink" from within R, you are the administrator.
Actually, you can also use the R function file.symlink to create symbolic links.

Since 2016 (Windows 10 Insiders build 14972), you can also make symbolic links without administrator rights if you enable the developer mode (in Settings>Update and Security>For developers).
This works in the Windows console with mklink, but it doesn't seem that R's file.symlink() works (as of R 4.0.3), possibly because of the dwFlags that needs to be set.
For calling it from R, I needed to add " when the path contains spaces:
shell(sprintf('mklink "%s" "%s"',
normalizePath(link, mustWork = FALSE),
normalizePath(original)
))
For directories, you can also consider the use of Sys.junction() which is somewhat equivalent to symlinks.

Related

Using rtools grep/pipe combination through a system call

I have a file called goodfile. Lets say the contents are
badline
goodline
badline
goodline
badline
badline
On a windows machine I want to filter this file to get only the "goodline"s before reading it to save on memory costs. Thankfully, the rtools installation comes with grep that should allow me to do that. I should be able to do
if(!pkgbuild::has_rtools()){
stop('install rtools')
}
rtoolsPath = pkgbuild::rtools_path()
grep = file.path(rtoolsPath,'grep.exe')
command = paste(grep, "goodline goodfile")
system(command)
and get
goodline
goodline
However when I try to pipe the output to a file by doing
command = paste(grep, "goodline goodfile > betterfile")
system(command)
I get
goodfile:goodline
goodfile:goodline
/usr/bin/grep: >: No such file or directory
/usr/bin/grep: betterfile: No such file or directory
This error message and the "betterfile" is not generated.
If I take the same command and run it on my command line, it just works, if I do the same system call with regular grep on R in linux machine it just works, so I can't see what the problem is.
I was able to find an alternative way to get the file by doing
system2(grep,
args = c('goodline','goodfile'),stderr = 'betterfile',stdout = 'betterfile')
but still curious why the pipe doesn't work

Julia on Windows. How to pass command line options to an executable file

I wish to call an executable file from Julia via Base.run (documented here) and pass command line options to that executable, but I can't figure out how to do that. In my specific example the executable is Notepad++ and the command line options are
-alwaysOnTop -nosession
This example code works, but doesn't pass the command line options:
function open_file_in_notepadpp()
exepath = "C:/Program Files (x86)/notepad++/notepad++.exe" #Default location on 64 bit Windows
command_line_options = "-alwaysOnTop -nosession "
filetoopen = "c:/temp/foo.txt"
Base.run(`$exepath $filetoopen`, wait = false)
end
I've tried incorporating command_line_options a fair number of ways using backticks, double quotes etc. to no avail, so for example neither of the lines below work:
Base.run(`$exepath $filetoopen`, `$command_line_options`,wait = false)
Base.run(`$exepath $command_line_options $filetoopen`,wait = false)
In the Windows Command Prompt the following works correctly:
"C:/Program Files (x86)/notepad++/notepad++.exe" -alwaysOnTop -nosession "c:/temp/foo.txt"
Could someone explain what I'm missing?
If you substitute a string that contains spaces to a command it will get quoted. Hence, your command line arguments will be quoted and you get
julia> `$exepath $filetoopen $command_line_options`
`'C:/Program Files (x86)/notepad++/notepad++.exe' c:/temp/foo.txt '-alwaysOnTop -nosession '`
I guess what you really need is
julia> command_line_options = ["-alwaysOnTop", "-nosession"]
2-element Array{String,1}:
"-alwaysOnTop"
"-nosession"
julia> `$exepath $filetoopen $command_line_options`
`'C:/Program Files (x86)/notepad++/notepad++.exe' c:/temp/foo.txt -alwaysOnTop -nosession`
Running the latter with run should work. Unfortunately I can't test it on my machine.
crstnbr's answer was correct, but he was unable to test on his machine. Here is the corrected code:
function open_file_in_notepadpp()
exepath = "C:/Program Files (x86)/notepad++/notepad++.exe" #Location if one follows the defaults in the notepad++ installer on 64 bit Wndows
command_line_options = ["-alwaysOnTop", "-nosession"] #Use an array to prevent the options being quoted
filetoopen = "c:/temp/foo.txt"
Base.run(`$exepath $filetoopen $command_line_options`,wait = false)
end

fread zipped file with 7z

I want to read in a file with fread in R. I have 7z installed.
I tried
fread(shell(cmd = '7z l test.txt.gz'), shell = 'cmd.exe'))
However I get the error
Error in fread(shell(cmd = paste0("7z x ", "\"", dest, "\""), shell = "cmd.exe")) :
'input' must be a single character string containing a file name, a command, full path to a file, a URL starting 'http[s]://', 'ftp[s]://' or 'file://', or the input data itself
I'm looking for something similar to:
fread(shell(cmd = 'unzip -cq test.zip', shell = 'cmd.exe'))
One work-around is to copy 7z.exe to the project folder. And try:
DT = fread(cmd = '7z e -so "test.zip"')
Some people suggested adding 7-zip to Windows PATH Environment Variable. But it did not work for me.

Running a Windows executable file from within R with command line options

I am trying to call a Windows program called AMDIS from within R using the call
system("C:/NIST08/AMDIS32/AMDIS_32.exe /S C:/Users/Ento/Documents/GCMS/test_cataglyphis_iberica/queens/CI23_Q_120828_01.CDF")
in order to carry out an analysis (specified using the /S switch) on a file called CI23_Q_120828_01.CDF, but it seems that no matter what I try the file is not loaded in correctly, presumably because the options are not passed along. Does anyone have a clue what I might be doing wrong?
Right now this command either
doesn't do anything,
makes AMDIS pop up, but it doesn't load the file I specify
gives me the error
Warning message:
running command 'C:/NIST08/AMDIS32/AMDIS_32.exe /S
C:/Users/Ento/Documents/GCMS/test_cataglyphis_iberica/queens/CI23_Q_120828_01.CDF'
had status 65535
(I have no idea what results in these different outcomes of the same command)
(the AMDIS command line options are described here at the page 8)
Cheers,
Tom
EDIT:
Found it had to do with forward vs backslashes - running
system("C:\\NIST08\\AMDIS32\\AMDIS_32.EXE C:\\Users\\Ento\\Documents\\GCMS\\test_cataglyphis_iberica\\queens\\CI23_Q_120828_01.CDF /S /E")
seems to work - thank you all for the suggestions!
You've heard of bquote , noquote , sQuote, dQuote , quote enquote and Quotes, well now meet shQuote!!! :-)
This little function call works to format a string to be passed to an operating system shell. Personally I find that I can get embroiled in backslash escaping hell, and shQuote saves me. Simply type the character string as you would on the command line of your choice ('sh' for Unix alikes like bash , csh for the C-shell and 'cmd' for the Windows shell ) wihtin shQuote and it will format it for a call from R using system:
shQuote("C:/NIST08/AMDIS32/AMDIS_32.exe /S C:/Users/Ento/Documents/GCMS/test_cataglyphis_iberica/queens/CI23_Q_120828_01.CDF" , type = "cmd" )
#[1] "\"C:/NIST08/AMDIS32/AMDIS_32.exe /S C:/Users/Ento/Documents/GCMS/test_cataglyphis_iberica/queens/CI23_Q_120828_01.CDF\""
More generally, you can use shQuote like this:
system( shQuote( "mystring" , type = c("cmd","sh") ) , ... )

Determine ghostscript version

I once did a blog on combining graphis with external programs and received a terrific comment from a reader (-click here-) on implementing this entirely within R with ghostscript as seen below. I have been using this a bit lately and am wanting to share it with others. I'd like to modify it to make the function more intuitive and detecting the ghostscript type is one mod I'd like to do but can't. The unix vs. windows is easy via .Platform. The sticking point is the windows 32 vs. 64 that I struggle with.
How can I use R to detect which ghostscript version (gswin32c or gswin64c) is running? Merely looking at the computer's specifications isn't good enough because I run gswin32c on a Win 64 machine. The idea is to remove the os argument entirely or set it to NULL and have the function try to access this information.
mergePDF <- function(infiles, outfile, os = "UNIX") {
version <- switch(os,
UNIX = "gs",
Win32 = "gswin32c",
Win64 = "gswin64c")
pre = " -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile="
system(paste(paste(version, pre, outfile, sep = ""), infiles, collapse = " "))
}
pdf("file1.pdf", width = 10, height = 8)
plot(1:10, col="red", pch = 19)
dev.off()
pdf("file2.pdf", width = 16, height = 8)
plot(1:10)
dev.off()
mergePDF("file1.pdf file2.pdf", "mergefromR.pdf", "Win32")
Tyler, dude. Have I been demoted from being a Stack Ove-R-flow peer to a "reader" of your blog? Or is that a promotion ;)
This feels a little hackish to me, but should get the job done. Add this as the first few lines of the function and remove the os argument:
testme <- c(UNIX = "gs -version",
Win32 = "gswin32c -version",
Win64 = "gswin64c -version")
os <- names(which(sapply(testme, system) == 0))
I've used the -version switch so that R doesn't try to load Ghostscript unnecessarily.
On my Ubuntu system, when I run this, os returns, as expected, UNIX, and on my Windows system where I have the 32-bit version of Ghostscript installed, it returns Win32. Try it out on your 64-bit machine running the 32-bit GS and let me know how it works.
Update
After reading the help pages for system() and system2(), I learned about Sys.which(), which seems to be exactly what you're looking for. Here it is in action on my Ubuntu system:
Sys.which(c("gs", "gswin32c", "gswin64c"))
# gs gswin32c gswin64c
# "/usr/bin/gs" "" ""
names(which(Sys.which(c("gs", "gswin32c", "gswin64c")) != ""))
# [1] "gs"
Thus, OS specification can be skipped entirely in the mergePDF() function:
mergePDF <- function(infiles, outfile) {
gsversion <- names(which(Sys.which(c("gs", "gswin32c", "gswin64c")) != ""))
pre = " -dBATCH -dNOPAUSE -q -sDEVICE=pdfwrite -sOutputFile="
system(paste(paste(gsversion, pre, outfile, sep = ""), infiles, collapse = " "))
}
You may want to do some error checking. If the length of gsversion is > 1 or is 0, for instance, you may want to stop the function and prompt the user to either install Ghostscript or to verify their Ghostscript version.

Resources