1

I have the following directory structure which I want to zip:

dir2zip
  subdir1
    file1.txt
  subdir2
    file2.txt
  subdir3
    file3.txt

I want to exclude subdir3, so I use the following command line:

zip -r dir2zip.zip dir2zip -x "dir2zip/subdir3/*"

When performing this on the prompt, the following correct output is received:

manfred@altair:~/data$ zip -r dir2zip.zip dir2zip -x "dir2zip/subdir3/*"
  adding: dir2zip/ (stored 0%)
  adding: dir2zip/subdir2/ (stored 0%)
  adding: dir2zip/subdir2/file2.txt (deflated 72%)
  adding: dir2zip/subdir1/ (stored 0%)
  adding: dir2zip/subdir1/file1.txt (deflated 68%)

But when I'm doing this in a script where the arguments are composed to a string, e.g. like this:

manfred@altair:~/data$ zipvar="-r dir2zip.zip dir2zip -x \"dir2zip/subdir3/*\""
manfred@altair:~/data$ echo $zipvar
-r dir2zip.zip dir2zip -x "dir2zip/subdir3/*"

...and I execute zip with this variable as argument, then the output is like this:

manfred@altair:~/data$ zip $zipvar
  adding: dir2zip/ (stored 0%)
  adding: dir2zip/subdir3/ (stored 0%)
  adding: dir2zip/subdir3/file3.txt (deflated 94%)
  adding: dir2zip/subdir2/ (stored 0%)
  adding: dir2zip/subdir2/file2.txt (deflated 72%)
  adding: dir2zip/subdir1/ (stored 0%)
  adding: dir2zip/subdir1/file1.txt (deflated 68%)

Here zip does also compress subdir3, it looks like when executing zip with arguments in a variable, it ignores some of them. Has anybody a hint how I can use zip with arguments generated by a script to a variable? I don't want to write all my zip commands explicitely in the script, the list would be much too long and too unflexible...

  • 2
    The problem is that quotes aren't processed when expanding a variable. So the quotes in the `-x` argument are being interpreted literally. See the linked question for how to do this correctly. – Barmar Mar 22 '23 at 20:28

1 Answers1

1

First of all, zip internally expands wildcard characters as find does. That is why your first example:

zip -r dir2zip.zip dir2zip -x "dir2zip/subdir3/*"

works well.

On the other hand, if you assign a variable zipvar to "-r dir2zip.zip dir2zip -x \"dir2zip/subdir3/*\"" and pass it to zip, the last argument is expanded as "dir2zip/subdir3/*", including the literal quotes as @Barmar comments. You can avoid it by saying:

set -o noglob           # avoid wildcard expansion
zipvar="-r dir2zip.zip dir2zip -x dir2zip/subdir3/*"
zip $zipvar

But it is not a good solution considering the case the pathnames include special characters such as whitespaces. Please try instead:

zipvar=(-r dir2zip.zip dir2zip -x "dir2zip/subdir3/*")
zip "${zipvar[@]}"

The usage of an array as arguments is a general and safer solution.

tshiono
  • 21,248
  • 2
  • 14
  • 22
  • 1
    Thanks for the hint with an array as zip arguments, this was new to me! Well, as the zipvar is also build from a script, e.g. like zipvar=(-r "${zip_dir[0]}.zip" "${zip_dir[0]}") and the argument is added via zipvar+=(-x \""${zip_dir[1]}"\"), again the problem with expansion occurs. So a combination of set -o noglob and zipvar+=(-x "${zip_dir[1]}") did it! Resetting wildcard expansion can be done with set +o noglob. – schweigerson Mar 24 '23 at 11:44