ant:如何执行目录中的每个文件的命令?
我想从一个Ant构build文件执行一个命令,为一个目录中的每个文件。
我正在寻找一个独立于平台的解决scheme。
我该怎么做呢?
当然,我可以用某种脚本语言编写脚本,但是这会增加项目的依赖性。
简答
将<foreach>
与嵌套的<FileSet>
Foreach需要ant-contrib 。
更新了最近的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>
这将阻止导致当前文件的$ {theFile}目标“bar”。
使用<apply>任务 。
它为每个文件执行一次命令。 通过文件集或任何其他资源指定文件。 <apply>是内置的; 不需要额外的依赖; 没有需要定制的任务实现。
也可以只运行一次命令,将所有文件作为参数一次追加。 使用parallel属性来切换行为。
对不起,迟到了一年。
塔斯洛angular ( Tassilo Horn )提出了一个没有反作用的方法( 原来的目标是在这里 )
基本上,因为没有像扩展<exec>一样扩展<java> (yet?),所以他build议使用<apply> (当然也可以在命令行中运行java程序)
这里有一些例子:
<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>
这里是使用javascript和ant scriptdef任务来完成这项工作的方法,因为scriptdef是核心ant任务,所以您不需要ant-contrib来执行此代码。
<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>
ant是邪恶的; 编写一个自定义的ant任务。
ant-contrib是邪恶的,因为它试图将ant从一个声明风格转换为一个命令风格。 但是xml使得一个废话的编程语言。
相比之下,一个自定义的ant任务允许你写一个真正的语言(Java),一个真正的IDE,在那里你可以编写unit testing,以确保你有你想要的行为,然后在你的构build脚本你想要的行为。
如果你关心编写可维护的ant脚本,这个咆哮就很重要。 如果你不在乎可维护性,尽一切办法做。 🙂
JTF
我知道这个post是真的老了,但现在有一些时间和ant版本通过有一种方法来做到这一点与基本的antfunction,我想我应该分享它。
它通过调用嵌套任务的recursionmacros定义(甚至可能调用其他macros)完成。 唯一的约定是使用一个固定的variables名(元素在这里)。
<project name="iteration-test" default="execute" xmlns="antlib:org.apache.tools.ant" xmlns:if="ant:if" xmlns:unless="ant:unless"> <macrodef name="iterate"> <attribute name="list" /> <element name="call" implicit="yes" /> <sequential> <local name="element" /> <local name="tail" /> <local name="hasMoreElements" /> <!-- unless to not get a error on empty lists --> <loadresource property="element" unless:blank="@{list}" > <concat>@{list}</concat> <filterchain> <replaceregex pattern="([^;]*).*" replace="\1" /> </filterchain> </loadresource> <!-- call the tasks that handle the element --> <call /> <!-- recursion --> <condition property="hasMoreElements"> <contains string="@{list}" substring=";" /> </condition> <loadresource property="tail" if:true="${hasMoreElements}"> <concat>@{list}</concat> <filterchain> <replaceregex pattern="[^;]*;(.*)" replace="\1" /> </filterchain> </loadresource> <iterate list="${tail}" if:true="${hasMoreElements}"> <call /> </iterate> </sequential> </macrodef> <target name="execute"> <fileset id="artifacts.fs" dir="build/lib"> <include name="*.jar" /> <include name="*.war" /> </fileset> <pathconvert refid="artifacts.fs" property="artifacts.str" /> <echo message="$${artifacts.str}: ${artifacts.str}" /> <!-- unless is required for empty lists to not call the enclosed tasks --> <iterate list="${artifacts.str}" unless:blank="${artifacts.str}"> <echo message="I see:" /> <echo message="${element}" /> </iterate> <!-- local variable is now empty --> <echo message="${element}" /> </target> </project>
主要特点需要在哪里:
- 在ant 1.9.1中引入了http://ant.apache.org/manual/ifunless.html ( 如果在macrodef中,信任ant的条件 )
- 子string,非常感谢如何在Ant中取出一个子string
- 内联macrodef元素。
我没有设法使分隔变异,但这可能不是一个主要的缺点。
您可以使用ant-contrib任务“for”在由任何分隔符分隔的文件列表上迭代,默认分隔符是“,”。
以下是显示这个的示例文件:
<project name="modify-files" default="main" basedir="."> <taskdef resource="net/sf/antcontrib/antlib.xml"/> <target name="main"> <for list="FileA,FileB,FileC,FileD,FileE" param="file"> <sequential> <echo>Updating file: @{file}</echo> <!-- Do something with file here --> </sequential> </for> </target> </project>
做什么blak3rbuild议和像这样定义你的目标类path
<taskdef resource="net/sf/antcontrib/antlib.xml"> <classpath> <fileset dir="lib"> <include name="**/*.jar"/> </fileset> </classpath> </taskdef>
lib是你存储jar的地方