Ant: How to execute a command for each file in directory?

133,095

Solution 1

Short Answer

Use <foreach> with a nested <FileSet>

Foreach requires ant-contrib.

Updated Example for recent ant-contrib:

<target name="foo">
  <foreach target="bar" param="theFile">
    <fileset dir="${server.src}" casesensitive="yes">
      <include name="**/*.java"/>
      <exclude name="**/*Test*"/>
    </fileset>
  </foreach>
</target>

<target name="bar">
  <echo message="${theFile}"/>
</target>

This will antcall the target "bar" with the ${theFile} resulting in the current file.

Solution 2

Use the <apply> task.

It executes a command once for each file. Specify the files by means of filesets or any other resource. <apply> is built-in; no additional dependency needed; no custom task implementation needed.

It's also possible to run the command only once, appending all files as arguments in one go. Use the parallel attribute to switch the behaviour.

Sorry for being late a year.

Solution 3

An approach without ant-contrib is suggested by Tassilo Horn (the original target is here)

Basicly, as there is no extension of <java> (yet?) in the same way that <apply> extends <exec>, he suggests to use <apply> (which can of course also run a java programm in a command line)

Here some examples:

  <apply executable="java"> 
    <arg value="-cp"/> 
    <arg pathref="classpath"/> 
    <arg value="-f"/> 
    <srcfile/> 
    <arg line="-o ${output.dir}"/> 

    <fileset dir="${input.dir}" includes="*.txt"/> 
  </apply> 

Solution 4

Here is way to do this using javascript and the ant scriptdef task, you don't need ant-contrib for this code to work since scriptdef is a core ant task.

<scriptdef name="bzip2-files" language="javascript">
<element name="fileset" type="fileset"/>
<![CDATA[
  importClass(java.io.File);
  filesets = elements.get("fileset");

  for (i = 0; i < filesets.size(); ++i) {
    fileset = filesets.get(i);
    scanner = fileset.getDirectoryScanner(project);
    scanner.scan();
    files = scanner.getIncludedFiles();
    for( j=0; j < files.length; j++) {

        var basedir  = fileset.getDir(project);
        var filename = files[j];
        var src = new File(basedir, filename);
        var dest= new File(basedir, filename + ".bz2");

        bzip2 = self.project.createTask("bzip2");        
        bzip2.setSrc( src);
        bzip2.setDestfile(dest ); 
        bzip2.execute();
    }
  }
]]>
</scriptdef>

<bzip2-files>
    <fileset id="test" dir="upstream/classpath/jars/development">
            <include name="**/*.jar" />
    </fileset>
</bzip2-files>

Solution 5

ant-contrib is evil; write a custom ant task.

ant-contrib is evil because it tries to convert ant from a declarative style to an imperative style. But xml makes a crap programming language.

By contrast a custom ant task allows you to write in a real language (Java), with a real IDE, where you can write unit tests to make sure you have the behavior you want, and then make a clean declaration in your build script about the behavior you want.

This rant only matters if you care about writing maintainable ant scripts. If you don't care about maintainability by all means do whatever works. :)

Jtf

Share:
133,095
ivan_ivanovich_ivanoff
Author by

ivan_ivanovich_ivanoff

!!! Netbeans 6.7 RELEASED !!! C is far better and easier than Java! Why? It is easier to use void pointers and to do pointer arithmetic, than explaining the basic concepts of OOP to a C programmer. Joke of the century: PHP is good, because it works... "PHP programming" is an oxymoron. There is no PHP programming. There is only PHP scriptkidding. There are two types of people who use PHP: - those who don't know other languages, - and those who HAVE TO use it Java is to JavaScript what Car is to Carpet. The LHC is the wrong answer to the technological singularity.

Updated on July 08, 2022

Comments

  • ivan_ivanovich_ivanoff
    ivan_ivanovich_ivanoff almost 2 years

    I want to execute a command from an Ant buildfile, for each file in a directory.
    I am looking for a platform-independent solution.

    How do I do this?

    Sure, I could write a script in some scripting language, but this would add further dependencies to the project.