[Wylug-help] quotes within quotes within bash

Craig Hopkins c.o.hopkins at gmail.com
Sun Nov 23 13:51:55 UTC 2008


2008/11/22 Smylers <Smylers at stripey.com>:
> Craig Hopkins writes:
>
>> MYARGS="-a --delete -e \"/usr/bin/ssh -p1234\" "
>
> So that's a single string, with some spaces and quotes in it.
>
>> Why is it that when I do
>>
>> echo $MYARGS
>
> That's splitting $MYARGS on spaces, and passing each chunk to echo as a
> separate argument.  echo then spits out each argument in turn --
> separating them with spaces (thereby making it impossible for you to
> distinguish those from the spaces that were in $MYARGS).
>
> You can see what's happening by using something which shows what each of
> its separate arguments are; here's a short Perl program which does that:
>
> #! /usr/bin/perl
> use Data::Dumper qw<Dumper>;
> print Dumper @ARGV;
>
> Save that in your path as args, make it executable, and you can do:
>
>  $ args $MYARGS
>
> which emits:
>
>  $VAR1 = '-a';
>  $VAR2 = '--delete';
>  $VAR3 = '-e';
>  $VAR4 = '"/usr/bin/ssh';
>  $VAR5 = '-p1234"';
>
> Note that arguments 4 and 5 are separate, and have the quote marks as
> part of them.
>
> For comparision, here's the desired output, which you get when passing
> those arguments directly on the command line:
>
>  $ args -a --delete -e "/usr/bin/ssh -p1234"
>  $VAR1 = '-a';
>  $VAR2 = '--delete';
>  $VAR3 = '-e';
>  $VAR4 = '/usr/bin/ssh -p1234';
>
> Note the shell interprets the quote marks, and never passes them to the
> program.
>
> So you need for $MYARGS to be interpreted by the shell like it does with
> typed input -- splitting on spaces but keep quoted phrases together and
> removing the quotes from what gets passed on.  Bash has a bult-in eval
> command which does just that:
>
>  $ eval args $MYARGS
>  $VAR1 = '-a';
>  $VAR2 = '--delete';
>  $VAR3 = '-e';
>  $VAR4 = '/usr/bin/ssh -p1234';
>
> Bingo!
>
> But there are various reasons why you might not want to use eval,
> especially if any of the contents of $MYARGS is coming from external
> sources.
>
> What you actually have is a list of separate arguments you wish to store
> in a variable.  So rather than collapsing them to a string which later
> has to be reparsed, instead store them in an array, one element per
> argument:
>
>  $ MYARGS=(-a --delete -e "/usr/bin/ssh -p1234")
>  $ args "${MYARGS[@]}"
>  $VAR1 = '-a';
>  $VAR2 = '--delete';
>  $VAR3 = '-e';
>  $VAR4 = '/usr/bin/ssh -p1234';
>
> Note that ${MYARGS[@]} needs quotes around it, to prevent your carefully
> preserved arguments from being split on spaces anyway.  That's just like
> after doing:
>
>  $ drink='Curiosity Cola'
>
> you still need the quotes in:
>
>  $ args "$drink"
>  $VAR1 = 'Curiosity Cola';
>
> to prevent it becoming:
>
>  $ args $drink
>  $VAR1 = 'Curiosity';
>  $VAR2 = 'Cola';
>
> Smylers

et voila! Much obliged :)

Craig



More information about the Wylug-help mailing list