3
\$\begingroup\$

In a bash script, I need to parse arguments that have the following form:

  1. The main arguments can be thought of as being a single argument, but I do not want to force users to quote the entire thing, so when the argument contains spaces I must be able to handle multiple arguments.

  2. One flag may be passed as-<flag> where<flag> can be an arbitrary word (without spaces)

  3. Finally, an external command, including its own options and flags may be passed. If so, this should be separated by a double dash.

For example,

my_command test

should result in

"$inp" == "test""$flag" == """$ext_command" == ""

and

my_command this is a test -new -- sed "s|a|b|"

should result in

"$inp" == "this is a test""$flag" == "new""$ext_command" == "sed \"s|a|b\""

I think the following script does what I want, but since it's my first bash script, I wanted to ask whether the script is idiomatic and whether I missed any border cases.

local inp=""local flag=""local ext_command=""local count="1"    local started=""for ido    count=$((count+1))    if [[ "$i" == '--' ]]    then        ext_command="${@:count}"        break    else        if [[ "$i" == -* ]];        then           flag=${i#*-}        else            if [ ! "$started" ]            then                inp="$i"                started=1            else                inp="$inp $i"            fi        fi    fidone
Toby Speight's user avatar
Toby Speight
88.7k14 gold badges104 silver badges327 bronze badges
askedNov 20, 2018 at 13:03
Bananach's user avatar
\$\endgroup\$
2
  • \$\begingroup\$Is it possible to have multiple flags?\$\endgroup\$CommentedNov 20, 2018 at 14:17
  • 1
    \$\begingroup\$@SolomonUcko no, not at the moment\$\endgroup\$CommentedNov 20, 2018 at 14:23

1 Answer1

3
\$\begingroup\$

Don't go against the language

The main arguments can be thought of as being a single argument, but I do not want to force users to quote the entire thing, so when the argument contains spaces I must be able to handle multiple arguments.

If you want to a value containing spaces as a single argument,then you and your users should double-quote it,otherwise Bash will perform word splitting.This is a fundamental principle in Bash,and it's better to play along with it than to go against.

Trying to go against will get you into all kinds of trouble.For example, what would you expect for?

my_command this      is   a test -new -- sed "s|a|b|"

That is, multiple spaces betweenwords.Those spaces will be lost,the script will behave the same way as if there was a single space in between.

Keep in mind that users will have to quote special characters anyway.You cannot shelter them from quoting.It's better to learn the basic rules of word splitting and quoting early,rather than trying to work around it with hacky solutions.

Assign arrays to arrays

This statement assigns an array to a non-array:

ext_command="${@:count}"

This way you lose the ability to expand the original value correctly quoted.

Take for example this input:

my_command test -new -- sed "s|a| |"

Notice the space in thesed pattern.

And let's say the script usesext_command like this:

ls | "$ext_command"

This will not work as intended (replacing "a" with spaces), because the original arguments are not preserved correctly.

Using an array you could leave this option open, that is:

ext_command=("${@:count}")

And then later:

ls | "${ext_command[@]}"

Minor points

Instead of this:

local inp=""

You can write simply:

local inp

Instead of this:

count=$((count+1))

You can write simply:

((count++))

Instead of this:

if [[ "$i" == '--' ]]then    ext_command="${@:count}"    breakelse    # a long block of code ...fi

It's more readable like this:

if [[ "$i" == '--' ]]then    ext_command="${@:count}"    breakfi# a long block of code ... but less deeply nested
answeredNov 21, 2018 at 19:31
janos's user avatar
\$\endgroup\$

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.