1

At my job, the edge node server that accesses our cluster is re-instantiated every day. This means I have to clone our repo and install a bunch of R packages every morning. I wrote a bash script (using https://github.com/eddelbuettel/littler to open R from the command line) to automate this and it works except for one hiccup.

Bash calls: r install.R

which opens an R session and calls the following command:

repos <- "http://... [our CRAN equivalent]"
install.packages("[package_name]",repos)

Now, normally, if I were entering this myself in R, I would get this as a response:

Installing package into ‘/usr/hdp/2.5.5.3-2/spark2/R/lib’ (as ‘lib’ is unspecified)
Warning in install.packages("[name_of_package]", repos = "http://...") :

'lib = "/usr/hdp/2.5.5.3-2/spark2/R/lib"' is not writable
Would you like to use a personal library instead?  (y/n) 

And I would say 'y,' followed by another 'y' when it suggests a library to create. However, when I do this from the bash script, it just says the library is not writable and aborts.

Two options I see here: 1) I tell it which library to write the packages in. I've tried this, and while the packages did go there, they arrived empty. Nothing was actually downloaded from the repo.

2) Somehow get the script to be able to pipe in the two affirmative responses I need in order to let R do its thing and create its own library.

Any suggestions on either of these would be much appreciated!

data princess
  • 1,130
  • 1
  • 23
  • 42

4 Answers4

1

There are multiple solutions to this. I will show two similar solutions.

The interactive script:

#!/bin/bash
# test.sh

printf "Response 1: "
read resp1
echo "You inserted $resp1"
printf "Response 2: "
read resp2
echo "You inserted $resp2"

To pipe two entries into this script, we can use a here string:

$ ./test.sh <<< $'yes\nno\n'
Response 1: You inserted yes
Response 2: You inserted no

Each entry is delimited from the other entries by the \n character. This string is sent to the standard input of the script.

Alternatively, you could also pipe the string into the scripts stdin stream:

$ printf 'yes\nno\n' | ./test.sh
Response 1: You inserted yes
Response 2: You inserted no
LTClipp
  • 526
  • 1
  • 4
  • 14
  • So the problem actually has more to do with "littler," the package I'm using to interface with R. In your example, piping to test.sh works fine but I'm actually running an R script from inside the shell script. And for some reason R doesn't even seem to give the prompt when I'm accessing it from the command line. – data princess Aug 04 '17 at 13:43
1

A different approach that works much better than what I originally posted:

In bash:

Create a specific library for installation (the same as the default R will want to create)

mkdir -p R/x86_64-pc-linux-gnu-library/3.3
Rscript --vanilla install_packages.R

In install_packages.R:

pkg_list <- # however you want to get this

for (pkg in pkg_list) {  
  install.packages(pkg, repos = "your_cran_mirror", 
                   lib = "R/x86_64-pc-linux-gnu-library/3.3") 
  if (!require(pkg, character.only = T)) {
    quit(save = "no", status = 1, runLast = FALSE)  
  }
}

Using this method, R will not prompt you and your script will run as intended.

data princess
  • 1,130
  • 1
  • 23
  • 42
0

Two options:

yes | r install.R

or:

{ echo y; echo y; } | r install.R
Jeff Schaller
  • 2,352
  • 5
  • 23
  • 38
  • Turns out you actually can't pipe into littler, as suggested here. But I appreciate the idea. I ended up just printing the necessary strings to the console before starting an R session so that I could quickly copy/paste a single block of code. Two steps instead of one, but better than ten. – data princess Aug 04 '17 at 15:47
0

NOTE: This technically works but is very clumsy and error-prone. Please see my other answer.

I figured out a way to do it.

First, create or modify .Rprofile. Add the installations and responses at the top of that file. For example:

repos = [CRAN or wherever you're sourcing from]
install.packages(package1, repos)
y
y
install.packages(package2, repos)
install.packages(package3, repos)
... # etc.

The 'y's should only be necessary for the first package, when R asks if you want to create a new library. The subsequent packages will also be dropped in there.

If you really want it to be hands-free and the script does other things after installing the R packages, you can add a quit() statement at the end, which will exit R and do whatever else you want the script to do. This might be annoying when you want to launch R later, so you'd want the script to pass around a couple different .Rprofiles.

Second, in your bash script, simply open R with R. The .Rprofile will be run immediately on startup, and the packages will be downloaded automatically.

data princess
  • 1,130
  • 1
  • 23
  • 42