22

I'm trying to run the following command using the 'exec' task in Ant:

ls -l /foo/bar | wc -l

Currently, I have my exec looking like this:

<exec executable="ls" outputproperty="noOfFiles">
    <arg value="-l" />
    <arg value="/foo/bar" />
    <arg value="|" />
    <arg value="wc" />
    <arg value="-l" />
</exec>

The 'ls' command looks to be working but it's having a hard time piping the output to 'wc'. Any suggestions?

Chris
  • 1,416
  • 18
  • 29
Steve Griff
  • 651
  • 1
  • 6
  • 16

3 Answers3

34

If you use sh -c as Aaron suggests, you can pass the whole pipeline as a single arg, effectively doing:

sh -c "ls -l foo/bar | wc -l"

If you use separate args, they are consumed by sh, not passed through to ls (hence you see just the current directory).

Note that on my system, ls -l includes a total as well as a list of the files found, which means the count shown is one more than the number of files. So suggest:

<exec executable="sh" outputproperty="noOfFiles">
    <arg value="-c" />
    <arg value="ls foo/bar | wc -l" />
</exec>
martin clayton
  • 76,436
  • 32
  • 213
  • 198
5

If you just want to count the files in a directory, don't use an external shell at all. Use the resourcecount task. Fast, compact, portable, and easy to read:

<resourcecount property="numfiles">
  <fileset dir="."/>
</resourcecount>

And you can of course customize the fileset to just include the specific files you need.

(There are actually very few cases where you need to spawn an external shell. Ant's built in I/O redirectors and input/output filter chains can often accomplish the same thing in a portable manner, even if it is sometimes a little verbose.)

JesperE
  • 63,317
  • 21
  • 138
  • 197
  • Thanks for the comment JesperE. I will look into resourcecount and replace my current solution with it. Cheers – Steve Griff Dec 10 '10 at 10:38
  • The other answer was the answer I was searching for, but +1 for providing the best answer to the original question. – undefined Mar 29 '13 at 00:28
2

You need someone to recognize and build the pipe. Try sh:

<exec executable="sh" outputproperty="noOfFiles">
    <arg value="-c" />
    <arg value="ls" />
    <arg value="-l" />
    <arg value="/foo/bar" />
    <arg value="|" />
    <arg value="wc" />
    <arg value="-l" />
</exec>
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • Hi Aaron - It's almost working! It seems to be ignoring the /foo/bar directory and just counting the amount of files in the current directory you are in on bash. – Steve Griff Oct 14 '10 at 09:16
  • Try `/bin/ls -1` (one, not i or L) and always use an absolute path. – Aaron Digulla Oct 14 '10 at 09:35
  • `ls -l /foo/bar | wc -l` should all be a single argument to /bin/sh. – JesperE Dec 10 '10 at 08:16
  • @JesperE: On the command line, I'd agree but not in Java. If you split the arguments, then the path can contain special characters (like spaces) and it will still work. – Aaron Digulla Jun 14 '12 at 10:08
  • You're missing my point. If you want `sh` to execute a shell script, you need to pass the script as *one* argument. Passing "ls" "-l" etc. to `sh` doesn't make sense. If you want to pass a path to `sh` which contains spaces, you need to quote it. – JesperE Jun 15 '12 at 10:05