11

Objective: to list files in all jars.

This works:

for f in `find . -name "*.jar"`; do jar tvf $f; done

This works too:

find . -name "*.jar" -exec jar tvf {} \;

This does not (it does not print any output):

find . -name "*.jar" | xargs jar tvf

Why does the latter not work?

Synesso
  • 37,610
  • 35
  • 136
  • 207

3 Answers3

16

Does this works

find . -name "*.jar"|xargs -n 1 jar -tvf
Rahul
  • 76,197
  • 13
  • 71
  • 125
9

The problem is that jar tvf only allows one file to be passed in.

The for loop runs the files one by one

jar tvf 1.jar; jar tvf 2.jar; ...

However, xargs tries to fit as many arguments on one line as possible. Thus it's trying the following:

jar tvf 1.jar 2.jar ...

You can verify this by placing an echo in your command:

for f in `find . -name "*.jar"`; do echo jar tvf $f; done
find . -name "*.jar" | xargs echo jar tvf

The proper solution is the tell xargs to only use one parameter per command:

find . -name "*.jar" | xargs -n 1 jar tvf

or

find . -name "*.jar" | xargs -I{} jar tvf {} # Find style parameter placement
Swiss
  • 5,556
  • 1
  • 28
  • 42
  • Thanks for the `-i` hint, nice. – sarnold Jul 08 '11 at 00:14
  • @sarnold you have to know that this argument (`-i`) is deprecated. see man xargs (`xargs (GNU findutils) 4.4.2`): `This option is deprecated; use -I instead.` There is no problem to use it in interactive mode but I would avoid it in scripts since it could disapear in a futur versions of xargs. – Lynch Jul 15 '11 at 01:46
6

It does not work because xargs invoke only one process with all arguments.

There is a way to invoke a new process for each argument using -I'{}'.

Try this to understand:

$ seq 10 | xargs echo
1 2 3 4 5 6 7 8 9 10
$ seq 10 | xargs -I'{}' echo {}
1
2
3
4
5
6
7
8
9
10
Lynch
  • 9,174
  • 2
  • 23
  • 34