2

I have a bash script that invokes the unzip command, and it needs to extract just the files in which the path to the file includes a subdirectory name that is one of 3 particular words: "a", "apple", and "applescript". So the file /a/b/c.txt and /com/apple/foo.txt should both be extracted.

I know that with normal bash command-line globs, I can use something like */{a,apple,applescript}/*.txt, but that's not applicable here because the unzip command is the thing that is evaluating the glob, rather than bash.

So a command like this doesn't work: unzip -oj file.zip '*/{a,apple,applescript}/*.txt'

One thing I tried was doing 3 separate unzip commands, sequentially, like this:

unzip -oj file.zip '*/a/*.txt'
unzip -oj file.zip '*/apple/*.txt'
unzip -oj file.zip '*/applescript/*.txt'

But that didn't work unless the zip file definitely contained both an a subdirectory and an apple subdirectory, and I have no guarantee that that will be the case.

What's the best way to make this work? Is there a way to do this in just one zip command, using a regular expression? Or alternatively, is there a way to make the 3 sequential commands work in the case when not all 3 subdirectory names are present in the zip file?

1
  • See this post for the differentiating between shell globs and regular expressions.
    – terdon
    Commented Feb 18, 2022 at 23:12

1 Answer 1

4

You can use a brace expansion, you only need to quote the asterisks to protect them from the shell’s glob expansion:

unzip -oj file.zip "*/"{a,apple,applescript}"/*.txt"

This will still exit with an error if one of the patterns isn’t matched; if that’s a problem, you can ignore exit status 11 (which indicates that files weren’t matched):

unzip -oj file.zip "*/"{a,apple,applescript}"/*.txt" || if [[ $? != 11 ]]; then
    echo Something bad happened
fi

You must log in to answer this question.

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