Let's do this! Tragically, existing answers are deficient in various obvious ways – including those both here and at a popular duplicate.
The accepted answer, for example, is Bash-specific (that's bad) and hardcodes the desired search pattern into a one-off 10-line shell function (that's even badder). The next most upvoted answer leverages FUSE-based pseudo-filesystems (that's patently insane). Likewise, the most upvoted answer at the aforementioned duplicate yields ambiguous, non-human-readable output (just... ugh).
I am Jack's wizened disapproval.
Working Code or It Didn't Happen
A new contender has entered the ring:
# str find_in_zip(str regex, str zip_filename1, ...)
#
# Find all paths contained in any zip-formatted archives with the passed
# filenames such that the relative pathnames of these paths in these
# archives match the passed extended regular expression.
function find_in_zip() {
(( $# >= 2 )) || {
echo 'Expected one extended regular expression and one or more zip filenames.' 1>&2
return 1
}
# Localize and remove the passed regex from the argument list.
local regex="${1}" zip_filename
shift
# For each passed zip filename...
for zip_filename in "${@}"; do
# Print the name of this filename for disambiguity.
echo "${zip_filename}:"
# Print all paths in this file matching this regex.
command unzip -l "${zip_filename}" |
command grep --extended-regexp --color=always "${regex}"
# Page the above output for readability.
done | less --RAW-CONTROL-CHARS
}
For usability, this function is called with the exact same signature as grep
. Namely, this function first accepts the regular expression to be searched for and then a variadic sequence of one or more zip filenames.
Likewise, this function has been tested under both Bash and zsh. Add the above code to either ~/.bashrc
or ~/.zshrc
and great zipfile glory shall be yours, ideally with set -e
enabled for sanity and strictness.
Examples or It Didn't Happen
To demonstrate, let's find the set of all classes embedded in I2P JAR files installed under Gentoo Linux whose names begin with exactly seven uppercase characters followed by one lowercase character – just 'cause:
$ find_in_zip '/[A-Z]{7}[a-z]' /usr/share/i2p/lib/*.jar
/usr/share/i2p/lib/addressbook.jar:
/usr/share/i2p/lib/BOB.jar:
/usr/share/i2p/lib/commons-el.jar:
/usr/share/i2p/lib/desktopgui.jar:
/usr/share/i2p/lib/i2p.jar:
568 01-16-2020 00:20 freenet/support/CPUInformation/AMDCPUInfo.class
236 01-16-2020 00:20 freenet/support/CPUInformation/VIACPUInfo.class
/usr/share/i2p/lib/i2psnark.jar:
/usr/share/i2p/lib/i2ptunnel.jar:
/usr/share/i2p/lib/jasper-compiler.jar:
/usr/share/i2p/lib/jasper-runtime.jar:
/usr/share/i2p/lib/jetty-continuation.jar:
/usr/share/i2p/lib/jetty-deploy.jar:
/usr/share/i2p/lib/jetty-http.jar:
/usr/share/i2p/lib/jetty-i2p.jar:
/usr/share/i2p/lib/jetty-io.jar:
/usr/share/i2p/lib/jetty-java5-threadpool.jar:
/usr/share/i2p/lib/jetty-rewrite-handler.jar:
/usr/share/i2p/lib/jetty-security.jar:
/usr/share/i2p/lib/jetty-servlet.jar:
/usr/share/i2p/lib/jetty-servlets.jar:
/usr/share/i2p/lib/jetty-sslengine.jar:
/usr/share/i2p/lib/jetty-start.jar:
/usr/share/i2p/lib/jetty-util.jar:
/usr/share/i2p/lib/jetty-webapp.jar:
/usr/share/i2p/lib/jetty-xml.jar:
/usr/share/i2p/lib/jstl.jar:
/usr/share/i2p/lib/mstreaming.jar:
/usr/share/i2p/lib/org.mortbay.jetty.jar:
/usr/share/i2p/lib/org.mortbay.jmx.jar:
/usr/share/i2p/lib/routerconsole.jar:
/usr/share/i2p/lib/router.jar:
5598 01-16-2020 00:20 org/cybergarage/upnp/ssdp/HTTPMUSocket.class
/usr/share/i2p/lib/sam.jar:
/usr/share/i2p/lib/standard.jar:
/usr/share/i2p/lib/streaming.jar:
/usr/share/i2p/lib/systray.jar:
You... probably wouldn't want to do that by hand.
zip -sf foo.zip | grep abc.jpg
to determine if an archive hasabc.jpg
; that should help. I don't have time to figure out the complete command now, but I'll try later if nobody else has answered