set stdout as a default output file and set deafult value to 3 in bash

Viewed 144

I am trying to use flags to set an output file for my bash program. I would like to make it possible in case I havent expliticly entered arguments to use stdout. Additionally, I set number of iterations. In case I do not provide this flag, I would like to set it to 3.

This is what I have:

while getopts i:o: option
do
case "${option}"
in
i) ITERATIONS=${OPTARG};;
o) OUTPUTF=${OPTARG};;
esac
done

docker-compose up -d
for i in {1..ITERATIONS}
    do docker-compose run specs | tee OUTPUTF
    sleep 1
done
docker-compose stop
2 Answers

The default values are easy; just assign them before the while loop. If the loop never overrides the value, they'll keep the default values.

The tricky part is figuring out a proper default for OUTPUTF. You can use /dev/stdout if your file system exposes, or maybe /dev/fd/0, but there isn't really a standard name you can use.

As an alternative, I'd recommend piping the output of docker-compose to a function whose definition can depend on the use of the -o option.

iterations=3
log_output () { cat; }  # Meant to ignore its argument
outputf=                # default value doesn't really matter

while getopts i:o: option; do
  case $option in
    i) iterations=$OPTARG ;;
    o) log_output () { tee "$1"; } 
       outputf=$OPTARG 
       ;;
  esac
done

docker-compose up -d
for ((i=0; i < $iterations; i++)); do  # Can't use parameters in a brace expression
    docker-compose run specs
    sleep 1
done | log_output "$outputf"
docker-compose stop

By default, log_output simply passes its input to cat, ignoring its argument. If you use -o, the log_output is redefined as a wrapper around tee and saves the output file name. Either way, log_output is called with "$outputf" as its argument.

If you want your iterations to have a default value, you can just set it to a default before the case statement with something like declare -i ITERATIONS=3;.

If I understand the first part of your question correctly, you to optionally also write the output to a file if one is provided to the bash scrip, right? If so, there are lots of ways to do this, but I think a simple solution would be to have OUTPUTF default to /dev/null and overwrite this output path if one is provided.

This results in the following:

declare -i ITERATIONS=3;
declare OUTPUTF=/dev/null;

while getopts i:o: option; do
    case "${option}" in
    i) ITERATIONS="${OPTARG}";;
    o) OUTPUTF="${OPTARG}";;
    esac
done

docker-compose up -d
for i in {1..ITERATIONS}; do
    docker-compose run specs
    sleep 1
done | tee "$OUTPUTF"
docker-compose stop

It is worth noting that I moved tee to the outside of the for loop because otherwise a new process will be spawned and the output file will be overwritten every iteration.

Related