Why does a backslash at the end of the line place undue whitespace?

I wanted:

#!/bin/bash
cmd --options 
    option=value,
    option=value,
    option=value,
    option=value

But running with bash -x I got:

cmd --options option=value, option=value, option=value, option=value

That causes an error.

How can I do this so bash doesn’t automatically place this blank space?

Asked By: rhuanpk

||

Well, you do have whitespace at the beginning of each line. This is not auto-removed by bash, although it is squeezed into one single space.

In order to completely avoid it, write the script as

#!/bin/bash
command --options 
opt1=val1,
opt2=val2,
opt3=val3
Answered By: AdminBee

If you need to pass a string like opt1=val1,opt2=val2,... as a single argument to a command, but want to have it in multiple lines in the script for editability, you could use an array as an intermediate step and then join all the array elements when running the command.

E.g.

opts=(
    opt1=val1    # no commas here 
    opt2=val2    # but comments also work
    etc.
)
(IFS=,
 echo somecmd --options "${opts[*]}"   # echo for demonstration
)

That prints somecmd --options opt1=val1,opt2=val2,etc.

(The first pair of parenthesis is part of the array assignment syntax, the second starts a subshell to shield the rest of the script from the modified IFS. That subshell might not be necessary, esp. if the script doesn’t do anything afterwards, or if you just reset IFS later or don’t use it at all.)

Obviously that requires a feature-rich shell with support for arrays. In addition to Bash, zsh would be fine. In ksh, you’d need to quote the strings (or at least the equal sign), so it doesn’t turn it into a struct-like compound variable.


If you require a POSIX sh compatible solution, the nearest equivalent to an array would be the list of positional parameters, but there’s only one set of them, and since set acts more or less like a regular command, you still need to remember the backslashes (and can’t use comments).

Instead, something like this should work:

args=$( <<EOF sed -e 's/^[[:space:]]*//' | tr 'n' ,
    opt1=val1
    opt2=val2
    etc.
EOF
)
args=${args%,}
echo somecmd --options "$args"  # echo for demonstration
Answered By: ilkkachu

If you want to be able to put each options in its own line, you may want to try another approach:

options="opt1=val1,"
options+="opt2=val2,"
options+="opt3=val3"
your_command --options "${options}"
# note: "command" being a bash builtin, I replaced it by "your_command"
# (command foo : bypasses any alias/function "foo" and instead launches "foo" from $PATH)
Answered By: Olivier Dulac

Another option:

#!/bin/bash
cmd --options "$(printf "%s" 
    "option=value," 
    "option=value," 
    "option=value," 
    "option=value"
)"

printf "%s" prints the arguments without any whitespace, so it results in:

cmd --options option=value,option=value,option=value,option=value

Some commands are also able to remove whitespace entirely on their own, provided it’s passed as a single argument. So simple quoting (to prevent word splitting) can be enough, for example ffmpeg seems to be fine with this:

ffmpeg -i somefile.mp4 -vf "
    hflip,
    vflip,
    hue=s=0
" result.mp4

But that depends on how the command you’re using handles these options.

Yet another option may be using --options itself multiple times (if your command allows that), in case of ffmpeg that doesn’t work, but sometimes it’s fine.

Answered By: frostschutz
Categories: Answers Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.