My aim is to find a jar entry, in the manifest of all jar, war, ear files recursively, in present directory, and subsequently print the archive name where match is found. I am printing the name of the archive, for which grep outputs a match.


find ./ -maxdepth 1 -type f -name "*.*ar" ! -name "*.tar" -exec zipgrep -qr "$classpathjarname" '{}' \; -print

works but takes a lot of time.

I have tried following command, but it fails:

find ./ -maxdepth 1 -type f -name "*.*ar" ! -name '*.tar' -print0 | xargs -r0 -P2 zipgrep -rq 'classpath.jar'

giving error

caution: filename not matched:  ./abc.jar
caution: filename not matched:  ./dsf.jar
/usr/bin/zipgrep: line 97: test: -eq: unary operator expected
/usr/bin/zipgrep: line 100: test: : integer expression expected
  • (1) Your title says "faster", but the body talks of an error. Was it ever working? (2) The command in the title differs from the body. Is that intentional? (3) What else have you tried already? Can you pull the command apart? Does the first part work by itself? What about the zipgrep… part? – Sparhawk Feb 6 '19 at 3:57
  • @Sparhawk , I have edited my question, to explain you more clearly. – Soumali Chatterjee Feb 6 '19 at 4:20

xargs is not as useful as it once was; find has been fixed so that it's no longer necessary. If you end your -exec command line with a + instead of a ;, find will invoke the command line on batches of the results itself. As mosvy pointed out, xargs does admittedly run in parallel with find, but I haven't found that to be very significant for my processing. It probably is for yours, however, since you're searching through compressed files in your loop.

find ./ -maxdepth 1 -type f -name "*.*ar" ! -name "*.tar" -exec zipgrep -lr "$classpathjarname" {} +

Your replacement didn't work, because you didn't understand it; the way your first version was working depended on zipgrep reporting via its exit status whether the file matched or didn't. This variant depends on zipgrep reporting the filenames that match, which is what the -l option does.

find ./ -maxdepth 1 -type f -name "*.*ar" ! -name "*.tar" -print0 | xargs -0 -P2 zipgrep -lr "$classpathjarname"

is how you'd do it with xargs. Your zipgrep error messages are because you apparently have a file that either isn't a zip file or is an empty zip file that the find is sending to zipgrep.

All that having been said, it's not going to be much faster than the first way, because the vast majority of the time spent by the first script was due to the fact that you're accessing the contents of compressed files and that takes time.

  • What do you mean by "The -print0 option is obsolete; find has been fixed."? Is this no longer an option? What do you mean by "fixed"? – Sparhawk Feb 6 '19 at 5:10
  • -print0 still exists. It's just that when you can do the same thing with an alternate syntax to -exec... Actually, I misspoke. There are a few corner cases where -print0 can still be useful, but they don't use xargs. If you have a command like tar which can take your nil separated output directly and do one command with unlimited input, that's still better than having find call the command with thousands of options. But that usage is somewhat rare. – Ed Grimm Feb 6 '19 at 5:14
  • xargs is not obsolete. – mosvy Feb 6 '19 at 5:46
  • @mosvy thank you for showing me the error of my thoughts regarding xargs. – Ed Grimm Feb 6 '19 at 6:04
  • @EdGrimm is it possible for me to output the name of the jar/war/ear file which contains the search string in its manifest, using xargs? I was able to fetch the same with find ./ -maxdepth 1 -type f -name "*.*ar" ! -name "*.tar" -exec zipgrep -qr "$classpathjarname" '{}' \; -print – Soumali Chatterjee Feb 6 '19 at 6:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.