Exit Powershell if R errors - r

I have a series of R files I'm calling in powershell. If one errors, I don't want it to carry on to try running the subsequent R scripts. The problem I have is capturing the R error in powershell, and using this to terminate the script. Any ideas?
I've tried this so far to no avail, as the error isn't being caught.
Powershell script:
# loop some scripts, try running them and if they fail then stop the process
foreach ($element in #(1,2,3)) {
Write-Host $element
try{
# minimal working eg of a script that stops early
Rscript -e "stop('error')"
}
catch {
Write-Host 'Rscript failed on run' $element'. Process killed in 10 seconds'
Start-Sleep 10
Exit
}
}
As it doesn't capture the error, the output message is:
1
Error: error
Execution halted
2
Error: error
Execution halted
3
Error: error
Execution halted
Any suggestions would be great! Thank you
EDIT:
Based off of the comment, am using this now (for future reference):
foreach ($element in #(1,2,3)) {
Write-Host $element
# minimal working eg of a script that stops early
Rscript -e "stop('error')"
if ($LastExitCode -ne 0){
Write-Host 'Rscript failed on run' $element'. Process killed in 10 seconds'
Start-Sleep 10
Exit
}
}

The errors are only available in the scope of the RScript not thrown into the PowerShell environment. You might consider to redirect the display output and evaluate the text but using the $LastExitCode is probably easiest.
(I don't have RScript installed but guess you can just capture the output like: $Result = Rscript -e "stop('error')".)
The exitcode can be controlled by the Status property of the Quit command and is apparently automatically set on a stop('error'):
foreach ($element in #(1,2,3)) {
Write-Host $element
# minimal working eg of a script that stops early
Rscript -e "stop('error')"
if ($LastExitCode -ne 0){
Write-Host 'Rscript failed on run' $element'. Process killed in 10 seconds'
Start-Sleep 10
Exit
}
}

Related

Grep R error message in bash to halt a pipeline

I have a pipeline I am working on. I have a wrappper.sh that pipes together various .R scripts. However, This pipeline will run through an error message. I want to add a way to grep our the word Error if True, shut down pipeline. I know I need an if/else statment, but dont know how to grep this info out of .R script running in bash.sh. See an example error.
Current script:
#!/bin/bash
#Bash script for running GeoMx Pipeline
####
# Install required R packages for pipeline
echo "installing R packages"
Rscript installPackages.R
echo "DONE! R packages installed"
#####
# Created required folders
echo "Creating Folders"
Rscript CreateFolder.R
echo "DONE! Folders created"
####
# Copy data over
cp -u -p Path/Initial\ Dataset.xlsx /PATO_TO
####
# Run Statistical Models
echo "Running Statistical Analysis"
Rscript GLM_EdgeR.R
echo "DONE! Statistical Models completed"
Example error:
Error in glmLRT(glmfit, coef = coef, contrast = contrast) :
contrast vector of wrong length, should be equal to number of coefficients in the linear model.
Calls: glmQLFTest -> glmLRT
Execution halted
What I want:
#!/bin/bash
#Bash script for running GeoMx Pipeline
####
# Install required R packages for pipeline
echo "installing R packages"
Rscript installPackages.R
if grep error == TRUE
then
echo "Fatal Error, STOP Pipeline"
STOP
else
echo "DONE! R packages installed"
#####
# Created required folders
echo "Creating Folders"
Rscript CreateFolder.R
if grep error == TRUE
then
echo "Fatal Error, STOP Pipeline"
STOP
else
echo "DONE! Folders created"
####
# Copy data over
cp -u -p Path/Initial\ Dataset.xlsx /PATO_TO
####
# Run Statistical Models
echo "Running Statistical Analysis"
Rscript GLM_EdgeR.R
if grep error == TRUE
then
echo "Fatal Error, STOP Pipeline"
STOP
else
echo "DONE! Statistical Models completed"
You don't need to grep for errors, you can test if last status-code was non-zero:
#!/bin/bash
Rscript CreateFolder.R
exit_code=$?
if test $exit_code -ne 0
then
echo "Fatal Error, STOP Pipeline"
exit $exit_code
else
echo "DONE! Folders created"
fi
If Rscript CreateFolder.R fails, bash script will exit with the same status-code.
Though if you have more of those conditions you want to check against, it makes sense to use set -e instead.
Exit immediately if a pipeline, which may consist of a
single simple command, a list, or a
compound command returns a non-zero status.
https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
Basically it makes your script run until something fails:
#!/bin/bash
set -e
Rscript installPackages.R
echo "DONE! R packages installed"
Rscript CreateFolder.R
echo "DONE! Folders created"
Rscript GLM_EdgeR.R
echo "DONE! Statistical Models completed"
With 2nd script, CreateFolder.R, failing, it will look like this:
~/r# ./wrappper.sh
[1] "OK"
DONE! R packages installed
Error: object 'will_fail' not found
Execution halted

Simulate wait's command -n flag in zsh

I am creating two shell jobs as follows
sleep 5 &
completion_pid=$!
sleep 40 && exit 1 &
failure_pid=$!
In bash I am able to get the exit code of the first job to finish by using the -n flag of wait's command
# capture exit code of the first subprocess to exit
wait -n $completion_pid $failure_pid
It seems however that this flag is not available in my MacOS Big Sur's version of wait (probably cause I am using zsh - ? )
▶ wait -n
wait: job not found: -n
Are there any alternative tools to do this that are also available on MacOS?
What perhaps is weird is that I am getting the same error when invoking a script containing wait -n as bash myscript.sh...
Since you are waiting by specifying PIDs, you can simply do a
wait $completion_pid $failure_pid

How to get an Rscript to return a status code in non-interactive bash mode

I am trying to get the status code out of an Rscript run in an non-interactive way in the form of a bash script. This step is part of larger data processing cycle that involves db2 scripts among other things.
So I have the following contents in a script sample.sh:
Rscript --verbose --no-restore --no-save /home/R/scripts/sample.r >> sample.rout
when this sample.sh is run it always returns a status code of 0, irrespective of if the sample.r script run fully or error out in an intermediate step.
I tried the following things but no luck
1 - in the sample.sh file, I added an if and else condition for a return code like the below, but it again wrote back 0 despite sample.r failing in one of the functions inside.
if Rscript --verbose --no-restore --no-save /home/R/scripts/sample.r >> sample.rout
then
echo -e "0"
else
echo -e "1"
fi
2 - I also tried a wrapper script, like in a sample.wrapper.sh file
r=0
a=$(./sample.sh)
r=$?
echo -e "\n return code of the script is: $a\n"
echo -e "\n The process completed with status: $r"
here also I did not get the expected '1' in the case of failure of the sample.r in an intermediate step on both the variables a and r. Ideally, i would like a way to capture the error (as '1') in a.
Could someone please advice how to get rscript to write '0' only in case of completion of the entire script without any errors and '1' in all other cases?
greatly appreciate the input! thank you!
I solved the problem by returning the status code in addition to echo. below is the code snipped from sample.sh script. In addition, in sample.R code i have added trycatch to catch the errors and quit(status = 1).
function fun {
if Rscript --verbose --no-restore --no-save /home/R/scripts/sample.r > sample.rout 2>&1
then
echo -e "0"
return 0
else
echo -e "1"
return 1
fi
}
fun
thanks everyone for your inputs.
The above code works for me. I modified it so that I could reuse the function and have it exit when there's an error
Rscript_with_status () {
rscript=$1
if Rscript --vanilla $rscript
then
return 0
else
exit 1
fi
}
run r scripts by:
Rscript_with_status /path/to/script/sample.r
Your remote script needs to provide a proper exit status.
You can make a 1st test by providing i.e. "exit 1" at the end of the remote script and see that it will make a difference.
remote.sh:
#!/bin/sh
exit 1
From local machine:
ssh -l username remoteip /home/username/remote.sh
echo $?
1
But the remote script should also provide to you the exit status of the last executed command. Experiment further by modifying your remote script:
#!/bin/sh
#exit 1
/bin/false
The exit status of the remote command will now also be 1.

Run shell script from within an R script on a windows machine

I have a R-script within which i call a shell script using system command and use the paste command to pass arguments to the shell script ( on unix machine) and i now would like execute the same R-script on a windows machine and am struggling to get it working
Here are the steps i followed
R code
source('C:\\Users\\xxxx\\Documents\\R\\R-3.5.2\\ms\\ms\\MS_Config.R')
if(is.null(git_version) | git_version == "" | length(git_version) == 0){
print('ERROR: EXECUTION STOPPED !!!')
print('PLEASE SPECIFY GITHUB TAG_ID')
stop()
}
print("test4444")
print(enable_data_pull)
print (getwd())
system(paste('C:\\Users\\xxxx\\Documents\\R\\R- 3.5.2\\ms\\ms\\MS_ALLM_Parallel_Runner.sh -c ', num_cores,
'-s ', snapshot_dt,
'-p ' , local_storage_path,
'-t ', tag,
'-g ', git_version,
'-y ', enable_data_pull
))
print ("after shell script execution")
I tried the following, but did not succeed
Installed cygwin and called the rscript from the cygwin terminal(PATH variable is updated to include R and its binaries)
rscript "C:\Users\xxxx\Documents\R\R-3.5.2\ms\ms\MS_Model_Kickoff.R"
Below is the error message that i see after the r-script attempts to run the shell script
'CreateProcess' failed to run 'C:\Users\xxxx\DOCUME~1\R\R-35~1.2\ms\ms\CONRM_~1.SH -c 25 -s 201811 -p C:\Users\xxxx\Documents\Test -t Analytical -g verModelRefit2.2.2 -y N'
what does the above error mean and how do i fix this and execute the shell script within from the R-script on windows machine?r

How to get the proper exit code from nohup

From the nohup documentation in info coreutils 'nohup invocation' it states:
Exit status:
125 if `nohup' itself fails, and `POSIXLY_CORRECT' is not set
126 if COMMAND is found but cannot be invoked
127 if COMMAND cannot be found
the exit status of COMMAND otherwise
However, the only exit codes I've ever gotten from nohup have been 1 and 0. I have a nohup command that's failing from within a script, and I need the exception appropriately...and based on this documentation I would assume that the nohup exit code should be 126. Instead, it is 0.
The command I'm running is: nohup perl myscript.pl &
Is this because perl is exiting successfully?
If your shell script runs the process with:
nohup perl myscript.pl &
you more or less forego the chance to collect the exit status from nohup. The command as a whole succeeds with 0 if the shell forked and fails with 1 if the shell fails to fork. In bash, you can wait for the background process to die and collect its status via wait:
nohup perl myscript.pl &
oldpid=$!
...do something else or this whole rigmarole is pointless...
wait $oldpid
echo $?
The echoed $? is usually the exit status of the specified PID (unless the specified PID had already died and been waited for).
If you run the process synchronously, you can detect the different exit statuses:
(
nohup perl myscript.pl
echo "PID $! exited with status $?" >&2
) &
And now you should be able to spot the different exit statuses from nohup (eg try different misspellings: nohup pearl myscript.pl, etc).
Note that the sub-shell as a whole is run in the background, but the nohup is run synchronously within the sub-shell.
As my understanding, the question was how to get the command status when it was running in nohup. As my experiences it was very little chance that you were able to get the COMMAND exit status even when it failed right away. Most time you just got the 'nohup COMMAND &' exit status unless you wait or synchronize as Jonathan mentioned. To check the COMMAND status right after nohup, I use:
pid=`ps -eo pid,cmd | awk '/COMMAND/ {print $1}'`
if [ -z $pid ]; then
echo "the COMMAND failed"
else
echo "the COMMAND is running in nohup"
fi

Resources