3

I am having trouble trying to describe my issue. Please bear with me. I have a script that calls a command. I need to optionally include an extra argument in the command line depending on the input file. I tried this:

    case "$model" in
    CNRM-CM6-1|CNRM-ESM2-1)
        trim_op="-selindexbox,2,361,2,293"
    ;;
    EC-Earth3)
        trim_op="-selindexbox,2,361,2,291"
    ;;
    IPSL-CM6A-LR)
        trim_op="-selindexbox,2,361,2,331"
    ;;
    MPI-ESM1-2-HR)
        trim_op="-selindexbox,2,801,3,403"
    ;;
    MPI-ESM1-2-LR)
        trim_op="-selindexbox,2,255,2,219"
    ;;
    NorESM2-LM)
        trim_op="-selindexbox,2,359,2,383"
    ;;
    *)
        trim_op=""
    ;;
esac

cdo -O remapcon,"$target_grid" "$trim_op" "$input_file" "$output_file"

but bash chokes on the empty word. What is the proper way of doing such a thing in bash? What I ended up doing was:

if [[ -z $trim_op ]] ; then
    cdo -O remapcon,"$target_grid" "$input_file" "$output_file"
else
    cdo -O remapcon,"$target_grid" "$trim_op" "$input_file" "$output_file"
fi

I am feeling quite ignorant right now. Is there a name for this? Every search I make turns up getop(s) which is not what I am looking for.

Stephen Kitt
  • 434,908
Brendan
  • 29
  • Is "$trim_op" quoted exactly like this in your actual code when cdo is called? This would call cdo with an empty 2nd argument. It is unclear whether the issue is that cdo can't be called with an empty 2nd argument, or whether you want to remove the argument if it's empty. – Kusalananda Oct 24 '22 at 13:56
  • cdo does not like the empty argument, but a lot of bash commands don't e.g. $ ls "". So I assumed it was not a cdo issue, per se. – Brendan Oct 25 '22 at 15:13
  • Ok, if a utility takes a string as an argument, it depends on the semantics of the utility whether getting an empty string is valid or not. The ls utility does not like an empty argument because there is no file or directory that has an empty name. – Kusalananda Oct 25 '22 at 15:35

4 Answers4

4

If you want to remove the "$trim_op" argument from the call to cdo if the variable is empty, you may do this:

cdo -O remapcon,"$target_grid" ${trim_op:+"$trim_op"} "$input_file" "$output_file"

The variable expansion ${trim_op:+"$trim_op"} expands to "$trim_op" (which is then further expanded) if the variable trim_op is set and the value in the variable is not empty.

Kusalananda
  • 333,661
2

"$trim_op" will expand to a single argument, regardless of the value the variable has. So if trim_op is set to an empty string, you get an empty argument, which probably doesn't work well with most programs.

That's different with the "$@" and "${array[@]}" expansions, which can produce a variable number of arguments. So, in a shell like Bash or ksh or zsh that supports arrays, use one of those to hold the arguments.

E.g. with Bash

unset args
case "$model" in
    CNRM-CM6-1|CNRM-ESM2-1)
        args+=("-selindexbox,2,361,2,293") ;;
    EC-Earth3)
        args+=("-selindexbox,2,361,2,291") ;;
#    *)
#        nothing here ;;
esac
args+=("$input_file" "$output_file")

cdo -O remapcon,"$target_grid" "${args[@]}"

Often one also meets this the other way around, trying to get two arguments out of one variable, which breaks if there's whitespace or glob characters there.

See also

ilkkachu
  • 138,973
  • Thanks so much. And thanks for those links. "how can I expand a quoted variable to nothing if it's empty" was the question I was trying to ask but could not find the words for. – Brendan Oct 25 '22 at 15:00
-1

Since there is no space in trim_op normally, you could:

cdo -O remapcon,"$target_grid" $trim_op "$input_file" "$output_file"

i.e. $trim_op is un-quoted.

if trim_op is empty, it should be run as cdo -O remapcon,"$target_grid" "$input_file" "$output_file"

koyeung
  • 94
  • 2
    Note that the issue with leaving parameter expansions unquoted is not with space, but with globbing characters and characters present in the $IFS special parameter (which by default contains space, but also tab and newline). In zsh, your answer is perfectly correct (even when the variable contains spaces or wildcards) as zsh only does empty removal upon unquoted parameter expansion, not split+glob. – Stéphane Chazelas Oct 24 '22 at 14:17
-1

Someone recently pointed out that an unquoted bash variable expansion, e.g., $ cdo -O remapcon,"$target_grid" ${trim_op} "$input_file" "$output_file" does exactly what I want. Doh!

Brendan
  • 29
  • 2
    That was actually mentioned in @koyeung's answer from Oct 24. It, well, works for nice values, but it's not really recommended because some day you'll have some_opt="--foo bar", with a space, and then word splitting applied to the unquoted expansion breaks it. Or glob characters will. The ${var:+"$var"} expansion in Kusalananda's answer works better because the inner double quotes prevent word splitting. – ilkkachu Oct 31 '22 at 12:10
  • Thanks so much for the clarification, ikkachu. Much appreciated! – Brendan Nov 01 '22 at 13:37