0

I’ve spent last hour or so trying to write a pretty simple bash script and I never felt so dumb.

So I have a list of strings (which are package selector specifications for a package manager, if that matters) which might contain asterisks. I need to build a command line preserving those asterisks and then call a program. Here is my naïve attempt:

xs="foo/bar */*"

xs_cmd=""
for x in $xs; do
  xs_cmd="$xs_cmd  -0 $x "
done

echo $xs_cmd

I need the echo call to be equivalent to

echo   -0 foo/bar    -0 '*/*' 

which outputs -0 foo/bar -0 */*.

P. S. In reality the first line is slightly more complex: xs="$some foo/bar */* $(get_others)".


If you run this script in a directory containing a/b, you’ll get -0 foo/bar -0 a/b instead.

When I change the last line to

echo "$xs_cmd"  # note the quotes

I get -0 foo/bar -0 a/b and, first of all that’s not what I want, since now I’m invoking echo with a single argument, and furthermore that tells me that the expansion is happening earlier, likely in the for loop.

But I can’t change the for line because

for x in "$xs"; do  # note the quotes

will just make the loop iterate only once: -0 foo/bar */* (there is a single -0) so adding those quotes is not an option for sure.

Now if I revert back to the original script and replace the first line with

xs="foo/bar '*/*'"  # note additional single quotes

I get -0 foo/bar -0 '*/*' (single quotes should’t be there).

It seems that I tried every combination of quotes and backslash-escapes of asterisks and I have literally no idea what to do now.

2 Answers 2

0

I used your original script, but with single quotes on the first line (only) and it worked as I think you want it (-0 before each file path):-

xs='foo/bar */*'

xs_cmd=""
for x in $xs; do
  xs_cmd="$xs_cmd  -0 $x "
done

echo $xs_cmd

You will probably find problems when you come to use it if there are embedded blanks in any of the file paths. If so change the command in the loop to:-

  xs_cmd="$xs_cmd  -0 \"$x\" "
9
  • Errr, no, this still performs expansion in the for loop and outputs a/b instead of */*. Another problem is that the first line is somewhat more complex in reality; I’ll update the question in a minute.
    – kirelagin
    Commented Oct 27, 2014 at 13:55
  • I thought you wanted it expanded in the for loop. I tested it on Ubuntu 14.04 and got -0 "foo/bar" -0 "dir/file" -0 "dir/file" ...
    – AFH
    Commented Oct 27, 2014 at 14:40
  • You might want to read my question again, especially the part right before the horizontal ruler that gives the desired output: no expansion should be performed; I need all the asterisks left in place.
    – kirelagin
    Commented Oct 27, 2014 at 15:13
  • OK. I have found something that works. Make your first line xs="foo/bar @/@", then after your for loop add the line xs_cmd=$(echo $xs_cmd|sed "s/@/\*/g"). If you can't find a character such as @ which is not in any of your file names, then use xs="foo/bar ///" and xs_cmd=$(echo $xs_cmd|sed "s-///-\*/\*-g"). I suggested using @ first as it is easier to generalise for other strings with asterisks.
    – AFH
    Commented Oct 27, 2014 at 16:28
  • So, now I have xs_cmd which is a string with some asterisks. How do I pass it to the command (echo in my example)? echo $xs_cmd will perform expansion. echo "$xs_cmd" will invoke echo with a single argument.
    – kirelagin
    Commented Oct 27, 2014 at 16:37
0

Depending on what you're trying to achieve, your either need to quote these */*:

xs="foo/bar '*/*'" #!

xs_cmd=""
for x in $xs ; do
    xs_cmd="$xs_cmd  -0 $x "
done

echo $xs_cmd
eval echo $xs_cmd
eval "echo $xs_cmd"

or use arrays, or both:

xs=("foo/bar" "*/*") #!

xs_cmd=""
for x in "${xs[@]}"; do
    xs_cmd="$xs_cmd  -0 '$x' " #!
done

echo "$xs_cmd"
eval "echo $xs_cmd"
1
  • As mentioned in my question, your first suggestion results in the following output: -0 foo/bar -0 '*/*', which means the quotes are literally passed to the program. Your second suggestion results in -0 'foo/bar' -0 'a/b' which both passes quotes to the program and performs expansion, while I need neither.
    – kirelagin
    Commented Nov 11, 2014 at 16:53

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .