BASH: how to pass a default argument if no arguments after the first were passed

5,840

Solution 1

I'd try to use bash variable substitution:

   test)
        shift
        docker exec -it $(docker-compose ps -q web) python manage.py test "${@-apps}"
        ;;

Other way is to check $* instead of $1:

case $* in 
    bash)
         ...
    test)
         docker exec -it $(docker-compose ps -q web) python manage.py test apps
         ;;
    test\ *)
         docker exec -it $(docker-compose ps -q web) python manage.py test "${@:2}"
         ;;

Solution 2

You can just reset your args however you want using set ...

case "$1" in 
    #...
    test)
        [ $# -lt 2 ] && set test apps
        docker exec -it $(docker-compose ps -q web) python manage.py $@
        ;;
esac

Solution 3

If arguments do not have spaces or newlines.
Transform the arguments into an string: "$*", and use that:

f(){ docker exec -it $(docker-compose ps -q web) "$@"; }

case "$*" in
    bash)       f /bin/bash                    ;;
    shell)      f python manage.py shell       ;;
    test)       f python manage.py test apps   ;;
    test\ ?*)   f python manage.py "$@"        ;;
esac

Using a function to manage code (not a variable) and remove repetition.

Solution 4

something like this would work well

if [ -z "$2" ]
  then
    echo "No argument supplied"
fi

Solution 5

case $1:$# in
(test:1)
    docker $(this is bad) python test apps;;
(test:$#)
    docker $(still bad) python "$@";;
(bash:$#)
    docker ...
esac
Share:
5,840

Related videos on Youtube

Chops
Author by

Chops

Updated on September 18, 2022

Comments

  • Chops
    Chops almost 2 years

    I have a bash script with a case statement in it:

    case "$1" in 
        bash)
            docker exec -it $(docker-compose ps -q web) /bin/bash
            ;;
        shell)
            docker exec -it $(docker-compose ps -q web) python manage.py shell
            ;;
        test)
            docker exec -it $(docker-compose ps -q web) python manage.py test "${@:2}"
            ;;
    esac
    

    On the test command, I want to pass the default argument of apps, but only if the user didn't pass any arguments other than test to the bash script.

    So, if the user runs the script like this:

    ./do test
    

    it should run the command

    docker exec -it $(docker-compose ps -q web) python manage.py test apps
    

    However, if they run the script like this:

    ./do test billing accounts
    

    it should run the command

    docker exec -it $(docker-compose ps -q web) python manage.py test billing accounts
    

    How can I test for the existence of arguments after the first argument?

    • jasonwryan
      jasonwryan over 8 years
      [[ $# -ne 1 ]]... or, more correctly, (( $# != 1 ))
  • Chops
    Chops over 8 years
    Did that edit mess it up? Should there be a : in "${@:-apps}"?
  • mikeserv
    mikeserv over 8 years
    @synic - the : will default even for a null valued second argument, and so doesnt answer the question asked. Without the : it will default only if there is no second argument.
  • mikeserv
    mikeserv over 8 years
    The test of $@ doesnt test for two arguments (and the white space would need escaping in the pattern anyway).
  • Costas
    Costas over 8 years
    @mikeserv Do you mean to change to $*?
  • mikeserv
    mikeserv over 8 years
    Not exactly. See the comments on BinaryZebra's answer. It still doesnt test for two arguments. It looks for a concatenation of argument(s) that starts with the pattern test\ . And so if the first argument starts w/ test\ it means nothing. Both of you guys should be using ? anyway. But it isnt a robist test regardless.
  • mikeserv
    mikeserv over 8 years
    Try like: ${#1}:$* and a pattern like 4:test?* - basically you cannot affirm a second argument based only on a test of either of $* or $@. Its not enough information.
  • Olivier Dulac
    Olivier Dulac over 8 years
    I'd rather say [ "$#" -ne "2" ] , as you could very well pass an empty 2nd argument : myscript foo "" bar baz # has 4 args, and the arg $2 is empty
  • mikeserv
    mikeserv over 8 years
    @OliverDulac - i dont think [ 2 -ne "$#" ] is a very useful test here. It negates every number of args but 2.
  • Olivier Dulac
    Olivier Dulac over 8 years
    @mikeserv: the poster tests only the 2nd arg, and say "no argument" (without s). If there can be more than 2, then if [ "$#" -lt 2 ]; then echo "Not enough arguments supplied: you need at least 2"; fi will be fine. The point of my comment being still the same: testing for the 2nd argument's length doesn't tell you how many arguments were supplied...
  • mikeserv
    mikeserv over 8 years
    @OliverDulac - true. The absence of a second argument does, though. [ "${2+:}" ] is probably the most simple way to robustly test for 2 or more arguments.