Passing Command Line Args in a Single Variable?

Hello All,

I have a Bash Script and an Expect script that together will SSH to another server and
do some stuff there... From within the Bash Script I process the Command Line Arguments,
which are Required Args and Optional Args.

When I call the Expect script from the Bash Script, I pass it all the required Args as
there own variables: i.e. $ip_address, $username, $password, $option...

Then, as I process any Optional Arguments I want to concatenate them into one Variable. Doing this
will remove a whole bunch of If statements from my script that would, for example, if the optional
argument "--restart" was given then execute the Expect Script with all the Required Args then
add the Optional Arg "--restart" to the end of the line that executes the script:

/path/to/script/myExpect_Script $ip_address $username $password $option --restart

So I would have to do this sort of thing for each optional argument, which could get very messy
because most of the Optional Args can be used together, which means a bunch of different combinations of Args can be used,
leaving me with a bunch of if statements...

So now what I have is, as I am checking all the Args from the command line, in the Bash Script... If
I find for example the "--restart" option I would say:

exe_command_args="$exe_command_args --restart"

Then I find the "add" option, I do:

exe_command_args="$exe_command_args add"

Lastly, I give it this final Arg:

exe_command_args="$exe_command_args command=\"command[check_alias]=/path/to/exe/check_myCmd -w 1 -c 5\""

Now I only have to have one line that makes a Call to the Expect Script like this...
(fyi when I make the call to execute the Expect script I add one last required option to the end of the line):

### Call the Expect Script
/path/to/script/myExpect_script $ip_address $username $password $option $exe_command --sshed

Now, while in the Expect Script I did a simple loop to check all the Args passed in and it seems it's treating the
Args within the variable "$exe_command_args" as one command line argument.
Here's the Loop from the Expect Script, and the Output:

#!/usr/bin/expect -f

puts "IN EXPECT SCRIPT:\n- Checking Command Line Args..."

### Loop through "$argv", which contains all the Arguments passed in as a list...
    set x 0
    foreach cmd_arg $argv {
        set tmp [lindex $argv $x]
        puts "\tARG $x: $tmp"
        incr x
    }
exit 101





________OUTPUT________

IN EXPECT SCRIPT:
- Checking Command Line Args...
    LINE 0: 192.168.5.181
    LINE 1: Matt
    LINE 2: Password
    LINE 3: add
    LINE 4:  command="command[check_alias]=/path/to/exe/check_myCmd -w 1 -c 5" comment="# COMMENT FOR NEW CHECK_COMMAND" --restart
    LINE 5: --sshed



So could there be anything I am doing wrong syntactically in the bash script when passing the
arguments? I was under the assumption that in order for an argument to be considered ONE arg,
if it contained any whitespace, that it needed to be quoted..?

And if I look at the Expect Output it seems to be quoted correctly and everything.

If anyone has anythoughts that would be great!
I really didn't want to have to change anything in the Expect Script of that way it assigns the
arguments to the variables...

***Sorry if I made this a little more confusing/complicated then it needed to be...

Thanks in Advance,
Matt

You cannot nest quotes inside quotes, and still expect them to work. Quotes do not work that way. Any methods you can kludge them into working with are, by definition, severe security holes, because if the shell is re-evaluating quotes, it will also re-evaluate backticks and the like. Someone could feed `rm -Rf ~/` into your program and it would do it.

Usually, if you're trying to do that, there's better ways to solve the problem which have been overlooked. But to know how to solve your problem, first we need to know what it is, and we don't.

We know how you're trying to solve it -- put a whole command in a variable -- but have no idea why you're trying to put a whole command in a variable. Usually, there's zero need to do so.

Hey Corona688, thanks for the reply.

Ok, that makes sense about there being a security risk for that...

The reason why I wanted to do that was because, like I mentioned in the OP, I have a bunch of
differnet possibilites for the optional command line args. Which in turn means a ton of differnt
combinations of arguments are possible. And because of that I would need a bunch of if statemnts
to check for these combinations (which is what I originally had)...

For example: Lets say that some of Optional Arguments are:
$option='start|stop|restart|status|add' --> Required Argument so $option will be on the executing line no matter what
command="..."
comment="..."
--restart
etc...

So for just these three args I would need all these If Statements...

if [[ $option =~ add ]]
 then
    if [ $comment -eq 1 ]
     then
        if [ $restart_option -eq 1 ]
         then
            /path/to/script/myExpect_script $ip_address $username $password $option command="..." comment="..." --restart --sshed
        elif [ $restart_option -eq 0 ]
         then
            /path/to/script/myExpect_script $ip_address $username $password $option command="..." comment="..." --sshed
        fi
    elif [ $comment -eq 0 ]
     then
        if [ $restart_option -eq 1 ]
         then
            /path/to/script/myExpect_script $ip_address $username $password $option command="..." --restart --sshed
        elif [ $restart_option -eq 0 ]
         then
            /path/to/script/myExpect_script $ip_address $username $password $option command="..." --sshed
    fi
fi

As you can see in the code above, this can get pretty messy, and that's only 3 of the options
that I'm checking in this example...

Since you said there's a security risk in doing it the way I was suggesting. Maybe I could just parse that option
that was passed from bash (i.e. $exe_command_args) and split it on whitespace, or something like that from
within the Expect Script..?

Thanks Again,
Matt

Hmmm. One way you can avoid quotes within quotes, and keep everything intact including spaces, is using the $1 $2 ... arguments. This will override your $1 $2 ... variables but if you're not using them anyway...

set -- # Set arguments completely blank
set -- a b c
echo $1 # should print a
echo $2 # should print b

set -- "a b" c
echo $1 # should print a b
echo $2 # should print c

# "$@" is a special var that ought to expand arguments w/o splitting
set -- "$@" "third arg" 
echo $1 # should print a b
echo $2 # should print c
echo $3 # should print third arg

So whenever you get a new argument, you can do set -- "$@" "next arg" "another arg" "Etc"

To use the arguments in order withour rearrangement or splitting, you can do $command "$@"

Again, note that "$@" is special. It does split, unlike other things in double-quotes -- but only on arguments, not on spaces, so the exact arguments you give are preserved.

And because of the way shell handles quotes, --arg="whatever" actually gets passed as --arg=whatever anyway. You do not need to insert quotes into there as long as no extra splitting happens, which will never happen with "$@".

Hey Corona688, thanks again for the reply...

Hummmm.... You given me some stuff to think about here lol, I'm going to play around with this a bit and I'll post back
with my results.

Thanks again for you suggestions/explanations, I appreciate your help!

Thanks Again,
Matt