1

While this is directly executed in terminal it works fine

zenity --info --text "pure info" --title "get info"

But this script doen't work what's wrong?

!/bin/bash
ZEN="--info --text \"pure info\" --title \"get info\""
zenity $ZEN

The script outputs like : "info in text and '"jeevan in title. It is skipping the remaining part.
Is it because the space (special character) loses it's special meaning inside double quotes?

2 Answers2

1

The difference is that the command zenity sees multiple arguments in the first case, and only one (including a lot of spaces) in the second.

With the following awk program, you can quickly output what the shell expands the arguments to. As it happens, zsh I could reproduce your problem:

% awk 'BEGIN {for (i in ARGV) print "ARGV["i"] =", ARGV[i]}' $ZEN                                               
ARGV[0] = awk
ARGV[1] = --info --text "pure info" --title "get info"

Whereas in bash it looks almost like it should look (notice that the quoted strings are split in words):

$ awk 'BEGIN {for (i in ARGV) print "ARGV["i"] =", ARGV[i]}' $ZEN
ARGV[0] = awk
ARGV[1] = --info
ARGV[2] = --text
ARGV[3] = "pure
ARGV[4] = info"
ARGV[5] = --title
ARGV[6] = "get
ARGV[7] = info"

There should be a shell word splitting option responsible for this behavior.

This, however, worked:

set -- --info --text "pure info" --title "get info"
zenity "$@"

Edit:

Shells are a bit stupid with word splitting by default, see the behavorior in my bash example above: "pure and info" are two separate words. As this is annoying in parsing of command line options, some special functionality has been created in the treatment of "$@. Quoting the bash manual, section Special Parameters:

   @      Expands  to  the positional parameters, starting from one.  When
          the  expansion  occurs  within  double  quotes,  each  parameter
          expands to a separate word.  That is, "$@" is equivalent to "$1"
          "$2" ...

I have not found a way to get the special treatment of $@ into normal variable expansion, but there could be a trick.

The set command sets the positional parameters, $1, $2, .... As such, the "Give me all"-version of positional parameters, $@, is available as well.

joepd
  • 2,397
1

One solution to this problem is to evaluate the whole expression so that the quotes inside the string are parsed:

eval zenity "$ZEN"

By the way, you may also use single quotes in variable definition instead of escaping double quotes:

ZEN='--info --text "pure info" --title "get info"'

And BTW2, you have missing # in front of !/bin/bash.

If you are using zsh then an alternative method is to split the parameter into words using shell parsing (taking into account quoting) with z flag, i.e.:

zenity "${(z)ZEN}"
jimmij
  • 47,140
  • If you have arrays, which both bash and zsh do, that's a simpler way of solving this. ZEN=(--info --text "pure info" --title "get info"); zenity "${ZEN[@]}" Using single quotes in the variable definition would not work. – Gilles 'SO- stop being evil' Jul 14 '15 at 15:07
  • @Gilles what would not work with single quotes? – jimmij Jul 14 '15 at 15:20
  • zenity $ZEN still would pass the arguments --info, --text, "pure, info", … just like what the asker tried. Oh, or did you mean this in combination with eval? That isn't clear. You should remove the bit about zsh, it's just confusing here. – Gilles 'SO- stop being evil' Jul 14 '15 at 15:25
  • I meant that he can use single quotes instead of escaping nested double-quotes - and this is only mentioned as a digression. – jimmij Jul 14 '15 at 15:37