[Wylug-help] quotes within quotes within bash

Smylers Smylers at stripey.com
Sat Nov 22 17:08:38 UTC 2008


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



More information about the Wylug-help mailing list