Iterating over all filenames in a directory in Ant

prasopes picture prasopes · Feb 19, 2014 · Viewed 8.6k times · Source

I need to iterate over all files in a directory. But I need just the name of each file, not absolute paths. Here's my attempt using ant-contrib:

<target name="store">
  <for param="file">
    <path>
      <fileset dir="." includes="*.xqm"/>
    </path>
    <sequential>
      <basename file="@{file}" property="name" />
      <echo message="@{file}, ${name}"/>
    </sequential>
  </for>              
</target>

The problem is that ${name} expression gets evaluated only once. Is there another approach to this problem?

Answer

Rebse picture Rebse · Feb 19, 2014

From ant manual basename : "When this task executes, it will set the specified property to the value of the last path element of the specified file"
Properties once set are immutable in vanilla ant, so when using basename task within for loop, the property 'name' holds the value of the first file. Therefore antcontrib var task with unset="true" has to be used :

<target name="store">
 <for param="file">
  <path>
   <fileset dir="." includes="*.xqm"/>
  </path>
  <sequential>
   <var name="name" unset="true"/>
   <basename file="@{file}" property="name" />
   <echo message="@{file}, ${name}"/>
  </sequential>
 </for>              
</target>

Alternatively use local task, when using Ant 1.8.x or later :

<target name="store">
 <for param="file">
  <path>
   <fileset dir="." includes="*.xqm"/>
  </path>
  <sequential>
   <local name="name"/>
   <basename file="@{file}" property="name" />
   <echo message="@{file}, ${name}"/>
  </sequential>
 </for>              
</target>

Finally you may use Ant Flaka instead of antcontrib :

<project xmlns:fl="antlib:it.haefelinger.flaka">
 <fl:install-property-handler />

 <fileset dir="." includes="*.xqm" id="foobar"/>

  <!-- create real file objects and access their properties -->
 <fl:for var="f" in="split('${toString:foobar}', ';')">
  <echo>
  #{  format('filename %s, last modified %tD, size %s bytes', f.tofile.toabs,f.tofile.mtime,f.tofile.size)  }
  </echo>
 </fl:for>

  <!-- simple echoing the basename -->
  <fl:for var="f" in="split('${toString:foobar}', ';')">
   <echo>#{f}</echo>
  </fl:for>  

</project>