6

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?

  • 1
    [[ $# -ne 1 ]]... or, more correctly, (( $# != 1 )) – jasonwryan Feb 1 '16 at 21:44
7

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}"
         ;;
  • Did that edit mess it up? Should there be a : in "${@:-apps}"? – synic Feb 1 '16 at 22:32
  • 2
    @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 Feb 1 '16 at 22:34
  • 1
    The test of $@ doesnt test for two arguments (and the white space would need escaping in the pattern anyway). – mikeserv Feb 2 '16 at 8:30
  • @mikeserv Do you mean to change to $*? – Costas Feb 2 '16 at 8:36
  • 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 Feb 2 '16 at 12:12
2
case $1:$# in
(test:1)
    docker $(this is bad) python test apps;;
(test:$#)
    docker $(still bad) python "$@";;
(bash:$#)
    docker ...
esac
2

something like this would work well

if [ -z "$2" ]
  then
    echo "No argument supplied"
fi
  • 1
    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 – Olivier Dulac Feb 2 '16 at 15:52
  • @OliverDulac - i dont think [ 2 -ne "$#" ] is a very useful test here. It negates every number of args but 2. – mikeserv Feb 2 '16 at 17:53
  • @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... – Olivier Dulac Feb 2 '16 at 18:28
  • @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. – mikeserv Feb 2 '16 at 19:07
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
1

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.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.