1

I am trying launch a Docker container that has as an entrypoint a python script that accepts a BBOX as an argument. I use a Bash script in order to automate the above.

Where the BBOX should be of this form: lonmin latmin lonmax latmax

Below is the Bash script

run.sh

#! /bin/bash

while getopts ":a" option; do
  case "${option}" in
    a) bbox="${OPTARG}" ;;
    \?)
      printf "Illegal option: -%s\n" "$OPTARG" >&2
      exit 1
      ;;
  esac
done
shift "$((OPTIND-1))"

# For a bbox inquiry
docker run -it  <docker_image_name:tag> --rm --bbox="$bbox" 

Where <docker_image_name:tag> is a docker image.

The arguments are passed into the following python script: core.py

 . . .

def parse_args():
    parser = argparse.ArgumentParser(
        prog='core',
        usage='%(prog)s [options] path',
        description='Download EO Products.',
        epilog='Enjoy downloading! :)')
    parser.add_argument("--bbox", type=float, nargs=4, help="lonmin latmin lonmax latmax")
    return parser.parse_args()
 . . .

If I ran the following command it fails ./run.sh -a 3 33 5 40 and raises the following error:

argument --bbox: expected 4 arguments

NOTE! The following command is successful and it wont raise any errors python core.py --bbox 3 33 5 40

EDIT The command ./run.sh -a "3 33 5 40" passes the arguments as a single string. Echoing the arguments in the Bash script:

    echo -e "BBOX VALUE: $bbox\n"
Output > BBOX VALUE: 3.0 33.0 5.0 40.0

    echo -e "BBOX VALUE WITH QUOTES: '$bbox'\n"
Output > BBOX VALUE WITH QUOTES: '3.0 33.0 5.0 40.0'

But it still raises the same error when it is passed to the python script.


Solution:

docker run -it  <docker_image_name:tag> --rm --bbox $bbox 
yeaaaahhhh..hamf hamf
  • 746
  • 2
  • 13
  • 34

1 Answers1

2

Based on the provided bash example, bbox="${OPTARG}" is always going to be an empty string as getopts ":a" defined a to be a simple flag (refer to this answer and associated posting on that thread for additional help). Even if you define getopts ":a:" such that -a will then accept an argument, calling ./run.sh -a 3 33 5 40 will result in ${bbox} having just 3 as the value (you can verify this yourself by echoing out the value e.g. echo "bbox=${bbox}") as again, it will only consume one argument. Essentially the Python program was being invoked with bbox flag set to a single empty string argument.

Since the arguments are going to be simple numbers without spaces, I will opt to pass them as a single quoted string in the bash version and then pass them unquoted to Python where its argparse will be able to handle the arguments separately, i.e.

File: run.sh

#!/bin/bash
while getopts ":a:" option; do
  case "${option}" in
    a)
      bbox="${OPTARG}";;
    \?)
      printf "Illegal option: -%s\n" "$OPTARG" >&2
      exit 1
      ;;
  esac
done
shift "$((OPTIND-1))"

echo "bash: bbox='${bbox}'"
python core.py --bbox $bbox

File: core.py

import argparse

def parse_args():
    parser = argparse.ArgumentParser(
        prog='core',
        usage='%(prog)s [options] path',
        description='Download EO Products.',
        epilog='Enjoy downloading! :)')
    parser.add_argument("--bbox", type=float, nargs=4, help="lonmin latmin lonmax latmax")
    return parser.parse_args()

if __name__ == '__main__':
    args = parse_args()
    print("python: args=%r" % args)

Execution:

$ # success
$ bash run.sh -a "1 2 3 4"
bash: bbox='1 2 3 4'
python: args=Namespace(bbox=[1.0, 2.0, 3.0, 4.0])
$ # failure in python as bash did not consume all arguments (lack of quotes)
$ bash run.sh -a 1 2 3 4
bash: bbox='1'
usage: core [options] path
core: error: argument --bbox: expected 4 arguments
$ # failure in python due to insufficient arguments in quotes
$ bash run.sh -a "1 2 3"
bash: bbox='1 2 3'
usage: core [options] path
core: error: argument --bbox: expected 4 arguments
$ # failure in bash
$ bash run.sh -b "1 2 3 4"
Illegal option: -b

If you must pass the arguments to bash as separate arguments (i.e. not a single quoted argument like in the above success example and as the first failure example due to lack of quotes), you will need to do one of the following suggestions found in the various answers in the following threads and adapt the script to pass the correct arguments to Python:

metatoaster
  • 17,419
  • 5
  • 55
  • 66
  • I have edited the question in order for you to have more input. I get no error when I ran the python script directly (look at **edit**). The problem occurs when I pass the arguments through docker . – yeaaaahhhh..hamf hamf Aug 16 '22 at 12:55
  • @yeaaaahhhh..hamfhamf note where I wrote where I "opt to pass them as a single quoted string in the bash version and then pass them unquoted to Python", and since you passed it to docker as `--bbox="$bbox"`, that might end up quoting them as one argument. If you can't unquote them into the four distinct arguments then consult the two threads I linked at the bottom as that is actually what you are trying to ask, whereas I am answering this way such that I am not duplicating the answer because this shortcut approach would be something I would figure out first. – metatoaster Aug 17 '22 at 02:41
  • Look at my example execution usage *very* carefully, and look at how in the bash script I called `python core.py --bbox $bbox` (note the lack of double quotes surrounding `$bbox`!) while you passed it to docker (not Python, as I don't know how or where the indirection from Docker to Python is set up in your scenario so I made zero assumptions) as `--bbox="$bbox"` - try passing instead `--bbox $bbox` which if that is passed as 5 distinct arguments then if docker pass them exactly to Python, it will accept it as such. – metatoaster Aug 17 '22 at 02:44
  • That is true. This `--bbox="$bbox"` outputs a string. I also tried with `--bbox=$bbox` which outputs a numeric sequence (which unfortunately is NOT recognized as 4 arguments). Still the same error. `--bbox=$bbox $bbox $bbox $bbox` also fails – yeaaaahhhh..hamf hamf Aug 17 '22 at 07:51
  • 1
    Remove the `=` sign, like I did in the comment. Please do read the answer carefully as this would save both our frustrations, I did make this very clear that `--box $bbox` will pass 5 distinct arguments - I should add that given that conforming input was passed. – metatoaster Aug 17 '22 at 08:05