I have the following bash script in which an R script is called
#!/bin/bash
declare -x a=33
declare -x b=1
declare -x c=0
Rscript --vanilla MWE.R $a $b $c
echo $a $b $c
I want to modify the bash variables in the R script and return their modified values in the bash script because I am then passing the modified variables somewhere else. The R script is
#!/usr/bin/env Rscript
args = commandArgs(trailingOnly=TRUE)
Rb = as.numeric(args[2])
Rc = as.numeric(args[3])
Rb = Rb + 1
Rc = Rc + 1
args[2]=Rb
args[3]=Rc
print(c(args[1],args[2],args[3]))
However, the output of the print and echo respectively are:
[1] "33" "2" "1"
33 1 0
which shows that the new values aren't passed from R to bash. What am I doing wrong?
As Rscript does not allow environment variable manipulation you will need to capture the R output from the bash program.
One of the many possibilities is to use an array:
#!/bin/bash
declare a=33
declare b=1
declare c=0
declare -a RESULT
RESULT=($(Rscript --vanilla MWE.R $a $b $c))
a=${RESULT[1]}
b=${RESULT[2]}
c=${RESULT[3]}
Related
Im trying to execute hive query in R using system command. This R function is called from a Bash script.
R Code
hivedata<-function(query)
{
data <- system(paste0("hive -S -e ", query), wait = TRUE,intern=TRUE)
if (identical(data, character(0))){data=NULL}
message("return value:")
message(data)
message("return value type:")
message(class(data))
return(cat(data))
}
if (length(query)>0 && is.na(query)==FALSE){
data=hivedata(query)
print(data)
}
Bash function
gethivedata(){
set -f #disable aterisk in sql getting expanded as filenames
query=$1
data=`Rscript hivedata.r "'$query'"`
echo $data
}
Calling function in Bash
totalcount=$(gethivedata " select count(*) from hivedb.hivetable ")
The outputs
[usr#host dir]$ totalcount=$(execute_sql " select count(*) from
hivedb.hivetable ")
return value:
0
return value type:
character
-------------------------------
[usr#host dir]$ echo $totalcount
0NULL
When cat is not used, the output value comes as [1]"0". Because R returns the index also with the output. When cat is used then the output becomes 0NULL. I want only the actual value which is "0"
What does [1] mean in the output of any command executed on R command line?
I am running an R script via bash script and want to return the output of the R script to the bash script to keep working with it there.
The bash is sth like this:
#!/bin/bash
Rscript MYRScript.R
a=OUTPUT_FROM_MYRScript.R
do sth with a
and the R script is sth like this:
for(i in 1:5){
i
sink(type="message")
}
I want bash to work with one variable from R at the time, meaning: bash receives i=1 and works with that, when that task is done, receives i=2 and so on.
Any ideas how to do that?
One option is to make your R script executable with #!/usr/bin/env Rscript (setting the executable bit; e.g. chmod 0755 myrscript.r, chmod +x myrscript.r, etc...), and just treat it like any other command, e.g. assigning the results to an array variable below:
myrscript.r
#!/usr/bin/env Rscript
cat(1:5, sep = "\n")
mybashscript.sh
#!/bin/bash
RES=($(./myrscript.r))
for elem in "${RES[#]}"
do
echo elem is "${elem}"
done
nrussell$ ./mybashscript.sh
elem is 1
elem is 2
elem is 3
elem is 4
elem is 5
Here is MYRScript.R:
for(iter in 1:5) {
cat(iter, ' ')
}
and here is your bash script:
#!/bin/bash
r_output=`Rscript ~/MYRscript.R`
for iter in `echo $r_output`
do
echo Here is some output from R: $iter
done
Here is some output from R: 1
Here is some output from R: 2
Here is some output from R: 3
Here is some output from R: 4
Here is some output from R: 5
I need to build up long command lines in R and pass them to system(). I find it is very inconvenient to use paste0/paste function, or even sprintf function to build each command line. Is there a simpler way to do like this:
Instead of this hard-to-read-and-too-many-quotes:
cmd <- paste("command", "-a", line$elem1, "-b", line$elem3, "-f", df$Colum5[4])
or:
cmd <- sprintf("command -a %s -b %s -f %s", line$elem1, line$elem3, df$Colum5[4])
Can I have this:
cmd <- buildcommand("command -a %line$elem1 -b %line$elem3 -f %df$Colum5[4]")
For a tidyverse solution see https://github.com/tidyverse/glue. Example
name="Foo Bar"
glue::glue("How do you do, {name}?")
With version 1.1.0 (CRAN release on 2016-08-19), the stringr package has gained a string interpolation function str_interp() which is an alternative to the gsubfn package.
# sample data
line <- list(elem1 = 10, elem3 = 30)
df <- data.frame(Colum5 = 1:4)
# do the string interpolation
stringr::str_interp("command -a ${line$elem1} -b ${line$elem3} -f ${df$Colum5[4]}")
#[1] "command -a 10 -b 30 -f 4"
This comes pretty close to what you are asking for. When any function f is prefaced with fn$, i.e. fn$f, character interpolation will be performed replacing ... with the result of running ... as an R expression.
library(gsubfn)
cmd <- fn$identity("command -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")
Here is a self contained reproducible example:
library(gsubfn)
# test inputs
line <- list(elem1 = 10, elem3 = 30)
df <- data.frame(Colum5 = 1:4)
fn$identity("command -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")
## [1] "command -a 10 -b 30 -f 4"
system
Since any function can be used we could operate directly on the system call like this. We have used echo here to make it executable but any command could be used.
exitcode <- fn$system("echo -a `line$elem1` -b `line$elem3` -f `df$Colum5[4]`")
## -a 10 -b 30 -f 4
Variation
This variation would also work. fn$f also performs substitution of $whatever with the value of variable whatever. See ?fn for details.
with(line, fn$identity("command -a $elem1 -b $elem3 -f `df$Colum5[4]`"))
## [1] "command -a 10 -b 30 -f 4"
Another option would be to use whisker.render from https://github.com/edwindj/whisker which is a {{Mustache}} implementation in R. Usage example:
require(dplyr); require(whisker)
bedFile="test.bed"
whisker.render("processing {{bedFile}}") %>% print
Not really a string interpolation solution, but still a very good option for the problem is to use the processx package instead of system() and then you don't need to quote anything.
library(GetoptLong)
str = qq("region = (#{region[1]}, #{region[2]}), value = #{value}, name = '#{name}'")
cat(str)
qqcat("region = (#{region[1]}, #{region[2]}), value = #{value}, name = '#{name}'")
https://cran.r-project.org/web/packages/GetoptLong/vignettes/variable_interpolation.html
My main question is how to split strings on the command line into parameters using a terminal command in Linux?
For example
on the command line:
./my program hello world "10 20 30"
The parameters are set as:
$1 = hello
$2 = world
$3 = 10 20 30
But I want:
$1 = hello
$2 = world
$3 = 10
$4 = 20
$5 = 30
How can I do it correctly?
You can reset the positional parameters $# by using the set builtin. If you do not double-quote $#, the shell will word-split it producing the behavior you desire:
$ cat my_program.sh
#! /bin/sh
i=1
for PARAM; do
echo "$i = $PARAM";
i=$(( $i + 1 ));
done
set -- $#
echo "Reset \$# with word-split params"
i=1
for PARAM; do
echo "$i = $PARAM";
i=$(( $i + 1 ));
done
$ sh ./my_program.sh foo bar "baz buz"
1 = foo
2 = bar
3 = baz buz
Reset $# with word-split params
1 = foo
2 = bar
3 = baz
4 = buz
As an aside, I find it mildly surprising that you want to do this. Many shell programmers are frustrated by the shell's easy, accidental word-splitting — they get "John", "Smith" when they wanted to preserve "John Smith" — but it seems to be your requirement here.
Use xargs:
echo "10 20 30" | xargs ./my_program hello world
xargs is a command on Unix and most Unix-like operating systems used
to build and execute command lines from standard input. Commands such as
grep and awk can accept the standard input as a parameter, or argument
by using a pipe. However, others such as cp and echo disregard the
standard input stream and rely solely on the arguments found after the
command. Additionally, under the Linux kernel before version 2.6.23,
and under many other Unix-like systems, arbitrarily long lists of
parameters cannot be passed to a command,[1] so xargs breaks the list
of arguments into sublists small enough to be acceptable.
(source)
I am having problem when trying to assign a value to a variable in a loop and trying to print it outside the loop using korn shell. I want to use that variable in later part of my script. So I am trying to test by printing the value of the dynamic variable. I just assigned to it from my array.
#!/usr/bin/ksh
clear
BINPATH=/usr/bin
SVR_LIST=servers_list
set -A SERVERS `cat $SVR_LIST`
typeset -i i=0
Sn=${#SERVERS[#]}
#echo "Number of servers in an array are .................." $Sn
while [ $i -lt ${#SERVERS[#]} ] ; do
#print ${SERVERS[$i]}
typeset -l s${i}=${SERVERS[$i]}
#eval echo "Value of Variable is" \${s$i}
#s=\${s$i}
(( i=i+1 ))
done
s=\${s$i}
eval echo "value of s is " $s
s=eval \${s0}
APPSERVER1=$s
echo $APPSERVER1
s=eval \${s1}
APPSERVER2=$s
echo $APPSERVER2
I am getting following error.
value of s is
./variableTest.sh[21]: ${s0}:not found
${s4}
./variableTest.sh[24]: ${s1}:not found
${s4}
here is working code…
#!/bin/ksh
clear
#BINPATH=/usr/bin
SVR_LIST=test
set -A SERVERS `cat $SVR_LIST`
typeset -i i=0
Sn=${#SERVERS[#]}
#echo "Number of servers in an array are .................." $Sn
while [ $i -lt ${#SERVERS[#]} ] ; do
#print ${SERVERS[$i]}
typeset -l s${i}=${SERVERS[$i]}
eval echo "Value of Variable is" \${s$i}
#s=\${s$i}
(( i=i+1 ))
done
#NOTE THIS LINE i value is i+1 here..
#so if you had last variable as s10=abc you are using s11 outside the loop in follwoing two lines..now its s10
let i=i-1
s=\${s$i}
eval echo "value of s is " $s
#CHANGES HERE
s=$s0
APPSERVER1=$s
echo $APPSERVER1
s=$s1
APPSERVER2=$s
echo $APPSERVER2
output...
Value of Variable is "credit":
Value of Variable is "wic":
Value of Variable is "wiccash":
Value of Variable is "sfmnp":
Value of Variable is "snap":
Value of Variable is "baked goods":
Value of Variable is "baked goods":
"credit":
"wic":