# argparse Command Line Argument Parsing

argparse is a command line argument parser inspired by Python’s “argparse” library. Use this with Rscript to write “#!”-shebang scripts that accept short and long flags/options and positional arguments, generate a usage statement, and set default values for options that are not specified on the command line.

In our working directory we have two example R scripts, named “example.R” and “display_file.R” illustrating the use of the argparse package.

bash$ ls

    display_file.R
    example.R

In order for a *nix system to recognize a “#!”-shebang line you need to mark the file executable with the `chmod` command, it also helps to add the directory containing your Rscripts to your path:

bash$ chmod ug+x display_file.R example.R

bash$ display_file.R example.R

Here is what “example.R” contains:

bash$ display_file.R example.R

    #!/usr/bin/env Rscript
    # Copyright 2012-2013 Trevor L Davis <trevor.l.davis@gmail.com>
    # Copyright 2008 Allen Day
    #
    #  This file is free software: you may copy, redistribute and/or modify it
    #  under the terms of the GNU General Public License as published by the
    #  Free Software Foundation, either version 2 of the License, or (at your
    #  option) any later version.
    #
    #  This file is distributed in the hope that it will be useful, but
    #  WITHOUT ANY WARRANTY; without even the implied warranty of
    #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    #  General Public License for more details.
    #
    #  You should have received a copy of the GNU General Public License
    #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    suppressPackageStartupMessages(library("argparse"))

    # create parser object
    parser <- ArgumentParser()

    # specify our desired options
    # by default ArgumentParser will add an help option
    parser$add_argument(
        "-v",
        "--verbose",
        action = "store_true",
        default = TRUE,
        help = "Print extra output [default]"
    )
    parser$add_argument(
        "-q",
        "--quietly",
        action = "store_false",
        dest = "verbose",
        help = "Print little output"
    )
    parser$add_argument(
        "-c",
        "--count",
        type = "integer",
        default = 5,
        help = "Number of random normals to generate [default %(default)s]",
        metavar = "number"
    )
    parser$add_argument(
        "--generator",
        default = "rnorm",
        help = "Function to generate random deviates [default \"%(default)s\"]"
    )
    parser$add_argument(
        "--mean",
        default = 0,
        type = "double",
        help = "Mean if generator == \"rnorm\" [default %(default)s]"
    )
    parser$add_argument(
        "--sd",
        default = 1,
        type = "double",
        metavar = "standard deviation",
        help = "Standard deviation if generator == \"rnorm\" [default %(default)s]"
    )

    # get command line options, if help option encountered print help and exit,
    # otherwise if options not found on command line then set defaults,
    args <- parser$parse_args()

    # print some progress messages to stderr if "quietly" wasn't requested
    if (args$verbose) {
        write("writing some verbose output to standard error...\n", stderr())
    }

    # do some operations based on user input
    if (args$generator == "rnorm") {
        cat(paste(rnorm(args$count, mean = args$mean, sd = args$sd), collapse = "\n"))
    } else {
        cat(paste(do.call(args$generator, list(args$count)), collapse = "\n"))
    }
    cat("\n")

By default `argparse` will generate a help message if it encounters `--help` or `-h` on the command line. Note how `%(default)s` in the example program was replaced by the actual default values in the help statement that `argparse` generated.

bash$ example.R –help

    usage: example.R [-h] [-v] [-q] [-c number] [--generator GENERATOR] [--mean MEAN] [--sd standard deviation]

    options:
      -h, --help            show this help message and exit
      -v, --verbose         Print extra output [default]
      -q, --quietly         Print little output
      -c number, --count number
                            Number of random normals to generate [default 5]
      --generator GENERATOR
                            Function to generate random deviates [default "rnorm"]
      --mean MEAN           Mean if generator == "rnorm" [default 0]
      --sd standard deviation
                            Standard deviation if generator == "rnorm" [default 1]

If you specify default values when creating your `ArgumentParser` then `argparse` will use them as expected.

bash$ example.R

    writing some verbose output to standard error...

    -1.27007527013558
    -1.404177922459
    -1.16881243149805
    1.08898914240976
    -0.664239841308519

Or you can specify your own values.

bash$ example.R –mean=10 –sd=10 –count=3

    writing some verbose output to standard error...

    22.0931200973524
    2.65033343471014
    17.2196537870774

If you remember from the example program that `--quiet` had `action="store_false"` and `dest="verbose"`. This means that `--quiet` is a switch that turns the `verbose` option from its default value of `TRUE` to `FALSE`. Note how the `verbose` and `quiet` options store their value in the exact same variable.

bash$ example.R –quiet -c 4 –generator=“runif”

    0.145101793343201
    0.769703338388354
    0.373955984367058
    0.494743616553023

If you specify an illegal flag then will print out a usage message and an error message and quit.

bash$ example.R –silent -m 5

    usage: example.R [-h] [-v] [-q] [-c number] [--generator GENERATOR] [--mean MEAN] [--sd standard deviation]
    example.R: error: unrecognized arguments: --silent -m 5

If you specify the same option multiple times then will use the value of the last option specified.

bash$ example.R -c 100 -c 2 -c 1000 -c 7

    writing some verbose output to standard error...

    0.0966196948937709
    0.181309664785241
    0.409183223624513
    -1.93238982399365
    0.109687464689486
    2.21907553582888
    2.03087995497323

`argparse` can also parse positional arguments. Below we give an example program `display_file.R`, which is a program that prints out the contents of a single file (the required positional argument, not an optional argument) and which accepts the normal help option as well as an option to add line numbers to the output.

bash$ display_file.R –help

    usage: display_file.R [-h] [-n] file

    positional arguments:
      file               File to be displayed

    options:
      -h, --help         show this help message and exit
      -n, --add_numbers  Print line number at the beginning of each line [default]

bash$ display_file.R –add_numbers display_file.R

    1 #!/usr/bin/env Rscript
    2 # Copyright 2012-2013 Trevor L Davis <trevor.l.davis@gmail.com>
    3 #
    4 #  This file is free software: you may copy, redistribute and/or modify it
    5 #  under the terms of the GNU General Public License as published by the
    6 #  Free Software Foundation, either version 2 of the License, or (at your
    7 #  option) any later version.
    8 #
    9 #  This file is distributed in the hope that it will be useful, but
    10 #  WITHOUT ANY WARRANTY; without even the implied warranty of
    11 #  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    12 #  General Public License for more details.
    13 #
    14 #  You should have received a copy of the GNU General Public License
    15 #  along with this program.  If not, see <http://www.gnu.org/licenses/>.
    16 suppressPackageStartupMessages(library("argparse"))
    17
    18 parser <- ArgumentParser()
    19 parser$add_argument(
    20  "-n",
    21  "--add_numbers",
    22  action = "store_true",
    23  default = FALSE,
    24  help = "Print line number at the beginning of each line [default]"
    25 )
    26 parser$add_argument("file", nargs = 1, help = "File to be displayed")
    27
    28 args <- parser$parse_args()
    29
    30 file <- args$file
    31
    32 if (file.access(file) == -1) {
    33  stop(sprintf("Specified file ( %s ) does not exist", file))
    34 } else {
    35  file_text <- readLines(file)
    36 }
    37
    38 if (args$add_numbers) {
    39  cat(paste(seq_along(file_text), file_text), sep = "\n")
    40 } else {
    41  cat(file_text, sep = "\n")
    42 }

bash$ display_file.R non_existent_file.txt

    Error: Specified file ( non_existent_file.txt ) does not exist
    Execution halted

bash$ display_file.R

    usage: display_file.R [-h] [-n] file
    display_file.R: error: the following arguments are required: file