How to check if arguments have been correctly pass

2019-06-03 11:16发布

问题:

I'm trying to write an R script that takes in 3 arguments when run with Rscript: input file name, whether it has a header or not (values are 'header' or 'no_header', and a positive integer (the number of replacements; its for a bootstrap application). So, when I run it this way:

Rscript bootstrapWithReplacement.R survival.csv header 50

it should, before running, check if: 1) The script indeed took in 3 parameters; 2) whether the first parameter is a file; 3) whether the second parameter has a 'header' or 'no_header' value, and 4) if the number passed is a positive integer.

Here is my code so far:

pcArgs      <- commandArgs()
snOffset    <- grep('--args', pcArgs)
inputFile <- pcArgs[snOffset+1]
headerSpec <- pcArgs[snOffset+2]    ## header/no_header
numberOfResamples <- pcArgs[snOffset+3] ## positive integer

check.integer <- function(N){
    !length(grep("[^[:digit:]]", as.character(N)))
}

if (!file_test("-f",inputFile)) {stop("inputFile not defined. Proper use: Rscript bootstrapWithReplacementFile.R survival.csv header 50.")}
if (!exists("headerSpec")) {stop("headerSpec not defined. Proper use: Rscript bootstrapWithReplacementFile.R survival.csv header 50.")} 
if (!exists("numberOfResamples")) {stop("numberOfResamples not defined. Proper use: Rscript bootstrapWithReplacementFile.R survival.csv header 50.")} 

if ((headerSpec != 'header') == TRUE & (headerSpec != 'no_header') == TRUE) {stop("headerSpec not properly defined. Correct values: 'header' OR 'no_header'.")}
if (check.integer(numberOfResamples) != TRUE | (numberOfResamples>0) != TRUE) {stop("numberOfResamples not properly defined. Must be an integer larger than 0.")}


if (headerSpec == 'header') {
    inputData<-read.csv(inputFile)
    for (i in 1:numberOfResamples) {write.csv(inputData[sample(nrow(inputData),replace=TRUE),], paste("./bootstrap_",i,"_",inputFile,sep=""), row.names=FALSE)}
}

if (headerSpec == 'no_header') {
    inputData<-read.table(inputFile,header=FALSE)
    for (i in 1:numberOfResamples) {write.table(inputData[sample(nrow(inputData),replace=TRUE),], paste("./bootstrap_",i,"_",inputFile,sep=""),
 sep=",", row.names=FALSE, col.names=FALSE)}
}

My problem is, the check for the existence of a file works, but for the header or integer don't.

Also, how can I, in the beginning, check if all three arguments have been passed?

Thanks!

回答1:

As Vincent said, you should use the trailingOnly argument to commandArgs to simplify things.
As Konrad said, never, ever, ever compare directly to TRUE and FALSE.
Also, use assertive for doing assertions.

library(assertive)
library(methods)    
cmd_args <- commandArgs(TRUE)

if(length(cmd_args) < 3)
{
  stop("Not enough arguments. Please supply 3 arguments.")
}
inputFile <- cmd_args[1]
if (!file_test("-f", inputFile)) 
{
  stop("inputFile not defined, or not correctly named."
}
headerSpec <- match.arg(cmd_args[2], c("header", "no_header"))
numberOfResamples <- as.numeric(cmd_args[3])
assert_all_numbers_are_whole_numbers(numberOfResamples)
assert_all_are_positive(numberOfResamples)

message("Success!")


回答2:

I managed to solve all the checks, here's how:

if ((length(pcArgs) == 8) == FALSE) {stop("Not enough arguments. Please supply 3 arguments. Proper use example: Rscript bootstrapWithReplacementFile.R survival.csv header 50.")}
if (!file_test("-f",inputFile)) {stop("inputFile not defined, or not correctly named. Proper use example: Rscript bootstrapWithReplacementFile.R survival.csv header 50.")}
if ((headerSpec != 'header') == TRUE & (headerSpec != 'no_header') == TRUE) {stop("headerSpec not properly defined. Correct values: 'header' OR 'no_header'.")}
if (check.integer(numberOfResamples) != TRUE | (numberOfResamples>0) != TRUE) {stop("numberOfResamples not properly defined. Must be an integer larger than 0.")}

Thanks everyone!