How to write a bash script that takes optional input arguments?

371,581

Solution 1

You could use the default-value syntax:

somecommand ${1:-foo}

The above will, as described in Bash Reference Manual - 3.5.3 Shell Parameter Expansion [emphasis mine]:

If parameter is unset or null, the expansion of word is substituted. Otherwise, the value of parameter is substituted.

If you only want to substitute a default value if the parameter is unset (but not if it's null, e.g. not if it's an empty string), use this syntax instead:

somecommand ${1-foo}

Again from Bash Reference Manual - 3.5.3 Shell Parameter Expansion:

Omitting the colon results in a test only for a parameter that is unset. Put another way, if the colon is included, the operator tests for both parameter’s existence and that its value is not null; if the colon is omitted, the operator tests only for existence.

Solution 2

You can set a default value for a variable like so:

somecommand.sh

#!/usr/bin/env bash

ARG1=${1:-foo}
ARG2=${2:-'bar is'}
ARG3=${3:-1}
ARG4=${4:-$(date)}

echo "$ARG1"
echo "$ARG2"
echo "$ARG3"
echo "$ARG4"

Here are some examples of how this works:

$ ./somecommand.sh
foo
bar is
1
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh ez
ez
bar is
1
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh able was i
able
was
i
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh "able was i"
able was i
bar is
1
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh "able was i" super
able was i
super
1
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh "" "super duper"
foo
super duper
1
Thu 19 May 2022 06:58:52 ADT

$ ./somecommand.sh "" "super duper" hi you
foo
super duper
hi
you

Solution 3

if [ ! -z $1 ] 
then 
    : # $1 was given
else
    : # $1 was not given
fi

Solution 4

You can check the number of arguments with $#

#!/bin/bash
if [ $# -ge 1 ]
then
    $1
else
    foo
fi

Solution 5

please don't forget, if its variable $1 .. $n you need write to a regular variable to use the substitution

#!/bin/bash
NOW=$1
echo  ${NOW:-$(date +"%Y-%m-%d")}
Share:
371,581
Abe
Author by

Abe

Updated on May 13, 2020

Comments

  • Abe
    Abe about 4 years

    I want my script to be able to take an optional input,

    e.g. currently my script is

    #!/bin/bash
    somecommand foo
    

    but I would like it to say:

    #!/bin/bash
    somecommand  [ if $1 exists, $1, else, foo ]
    
    • Ansel Halliburton
      Ansel Halliburton over 12 years
      Bash or POSIX? With Bash, there are more possibilities
    • Abe
      Abe over 12 years
      @Pumbaa80 bash - I have updated the tags.
    • Vadzim
      Vadzim over 8 years
    • Vadzim
      Vadzim over 8 years
    • Joonho Park
      Joonho Park over 3 years
      I want to say that the this subject is not about the optional argument but a positional argument with default value. This terminology gives much confusion. "Optional argument" means it would be ok whether those arguments exist in the command line or not.
  • vmpstr
    vmpstr over 12 years
    Technically, if you pass in an empty string '' that might count as a parameter, but your check will miss it. In that case $# would say how many parameters were given
  • l0b0
    l0b0 over 12 years
    Please note the semantic difference between the above command, "return foo if $1 is unset or an empty string", and ${1-foo}, "return foo if $1 is unset".
  • l0b0
    l0b0 over 12 years
    -n is the same as ! -z.
  • jwien001
    jwien001 almost 10 years
    Can you explain why this works? Specially, what's the function/purpose of the ':' and '-'?
  • Jubbles
    Jubbles almost 10 years
    @jwein001: In the answer submitted above, a substitution operator is used to return a default value if the variable is undefined. Specifically, the logic is "If $1 exists and isn't null, return its value; otherwise, return foo." The colon is optional. If it's omitted, change "exists and isn't null" to only "exists." The minus sign specifies to return foo without setting $1 equal to 'foo'. Substitution operators are a subclass of expansion operators. See section 6.1.2.1 of Robbins and Beebe's Classic Shell Scripting [O'Reilly] (shop.oreilly.com/product/9780596005955.do)
  • Vadzim
    Vadzim over 8 years
    Brad's answer above proves that argument variables can also be substituted without intermediate vars.
  • Garren S
    Garren S over 7 years
    +1 for noting the way to use a command like date as the default instead of a fixed value. This is also possible: DAY=${1:-$(date +%F -d "yesterday")}
  • Ohad Schneider
    Ohad Schneider over 7 years
    @Jubbles or if you don't want to buy an entire book for a simple reference... tldp.org/LDP/abs/html/parameter-substitution.html
  • sautedman
    sautedman over 7 years
    This answer would be even better if it showed how to make the default be the result of running a command, as @hagen does (though that answer is inelegant).
  • Raffi Khatchadourian
    Raffi Khatchadourian over 6 years
    Ah, ok. The - confused me (is it negated?).
  • Brad Parks
    Brad Parks over 6 years
    Nope - that's just a weird way bash has of doing the assignment. I'll add some more examples to clarify this a bit... thanks!
  • DanielW
    DanielW about 5 years
    If the subcommand possible takes multiple paramters, then: somecommand ${@-foo}
  • Eliezer
    Eliezer over 4 years
    I get different results using -n and ! -z so I would say that is not the case here.
  • glenn jackman
    glenn jackman over 4 years
    because you failed to quote the variable, [ -n $1 ] will always be true. If you use bash, [[ -n $1 ]] will behave as you expect, otherwise you must quote [ -n "$1" ]
  • Joonho Park
    Joonho Park over 3 years
    I am frustrated why this is optional argument. If you use $1 for a variable, it is positional argument not optional argument. If a command can receive an optional argument of -a -b -c then it should work with "command -a 10", "command -b ten", "command -c abc" and "command -a 7 -c aaa". If it works always with three arguments such as "command 10 ten abc", it is not a optional argument.
  • Anh-Thi DINH
    Anh-Thi DINH over 2 years
    For ones like me: forget the ":" in the code, it's not required, replace it with your real commands!
  • Joonho Park
    Joonho Park over 2 years
    It looks this is the limit of bash argument. Using python terminology, this is not optional, it is positional. It is just a positional argument with default values. Is there no really optional argument in bash?
  • Brad Parks
    Brad Parks over 2 years
    you may be able to use getopts to get what you want - Here's 2 stackoverflow answers that go into greater detail: dfeault values and inside a function
  • mirekphd
    mirekphd about 2 years
    Note also, that to confuse even more (with JSON/python dicts) no space is permitted anywhere, e.g. after the colon and/or after/before the dash... where is the principle of least astonishment here?:)
  • Brad Parks
    Brad Parks about 2 years
    good point @mirekphd - I added an example showing how to put spaces in a default value. You can use single quotes if you want a literal value, or double quotes if you want variables to be interpolated