Alex Rivera | Logout

Shell variable with spaces , quoting for single command line option

Asked 2009-11-12T17:40:03.023
16

Autoconf scripts have trouble with a filename or pathname with spaces. For example,

./configure CPPFLAGS="-I\"/path with space\""

results in (config.log):

configure:3012: gcc  -I"/path with space"  conftest.c  >&5
gcc: with: No such file or directory
gcc: space": No such file or directory

The compile command from ./configure is ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' and I am not able to modify this (I could perhaps, but working around autoconf in this way is not a general solution).

I think it comes down to getting a shell variable that contains spaces to be parsed as a single command line variable rather than split at spaces. The simplest shell example I can come up with is to create a file with spaces and attempt to list is with ls with a shell variable as the argument to ls:

$ touch "a b"
$ file="a b"
$ ls $file
ls: a: No such file or directory
ls: b: No such file or directory

This works, but is illegal since in autoconf I can't modify the shell code:

$ ls "$file"
a b

None of the following attempts at quoting things work:

$ file="\"a \"b"; ls $file
ls: "a: No such file or directory
ls: b": No such file or directory
$ file="a\ b"
$ file="a\\ b"
$ file="`echo \\"a b\\"`"

and so on.

Is this impossible to accomplish in shell scripts? Is there a magical quoting that will expand a shell variable with spaces into a single command line argument?

Edit
Report

1 Answer

4

if you give command

 gcc -I"x y z"

in a shell then certainly the single command line parameter "-Ix y z" will be passed to gcc. There is no question to that. That's the whole meaning of double quotes: things inside double quotes are NOT subject to field splitting, and so not subject to $IFS either, for instance.

But you need to be careful about the number of quotes you need. For instance, if you say

 file="a b" # 1

and then you say

 ls $file # 2

what happens is that the file variable's contents are 'a b', not '"a b"', because the double quotes were "eaten" when line 1 was parsed. The replaced value is then field-separated and you get ls on two files 'a' and 'b'. The correct way to get what you want is

 file="a b"; ls "$file"

Now the problem in your original case is that when you set a variable to a string that CONTAINS double quotes, the double quotes are later not interpreted as shell quote symbols but just as normal letters. Which is why when you do something like

 file="\"a b\""; ls $file

actually the shell tokenizes the contents of the file variable into '"a' and 'b"' when the ls command is analyzed; the double quote is no longer a shell quote character but just part of the variable's contents. It's analogous to that if you set

 file="\$HOME"; ls $file

you get an error that '$HOME' directory does not exist---no environment variable lookup takes place.

So your best options are

  1. Hack autoconf
  2. Do not use path names with spaces (best solution)
answered 2009-11-13T17:03:44.353

Your Answer