Ant:如何为目录中的每个文件执行命令?

iva*_*off 95 ant build-automation file-io build-process

我想从Ant构建文件中为目录中的每个文件执行一个命令.
我正在寻找一个独立于平台的解决方案.

我该怎么做呢?

当然,我可以使用某种脚本语言编写脚本,但这会为项目添加更多依赖项.

Ale*_*lex 86

使用<apply>任务.

它为每个文件执行一次命令.通过文件集或任何其他资源指定文件.<apply>是内置的; 不需要额外的依赖; 不需要自定义任务实现.

也可以只运行一次命令,将所有文件作为参数一次性附加.使用parallel属性切换行为.

抱歉一年到晚了.

  • <apply>的问题在于它只执行外部系统命令.它不会直接做任何anty的东西.不清楚原始问题是否与之相关.基本上你必须使用<apply>或<foreach>来处理两种不同的情况......这完全是愚蠢的. (7认同)
  • 我刚刚在2011年发现它很有用,所以非常感谢! (4认同)

bla*_*k3r 60

简答

使用<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>
Run Code Online (Sandbox Code Playgroud)

这将使用$ {theFile}来调用目标"bar",从而生成当前文件.

  • 哦,跛脚......这是一个Ant-Contrib任务.所以,你必须安装一些东西.见这里:http://ant-contrib.sourceforge.net/ (4认同)
  • 这个例子来自于它被包含在ant-contrib之前的foreach.在http://ant.1045680.n5.nabble.com/Using-foreach-td1354624.html上有一个很好的例子我将更新该示例. (3认同)
  • 嵌套的fileset元素已被删除,而是使用嵌套路径 (2认同)

Jmi*_*ini 27

Tassilo Horn提出了一种没有ant-contrib的方法(原始目标在这里)

基本上,因为没有<java>(还有?)的扩展,就像<apply> extends <exec>一样,他建议使用<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> 
Run Code Online (Sandbox Code Playgroud)

  • 链接坏了. (3认同)
  • 虽然在原始问题中明确要求,但这不是非常独立的平台...... (2认同)

ams*_*ams 17

以下是使用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>
Run Code Online (Sandbox Code Playgroud)

  • 对于那些在 JDK8 或更高版本中尝试此操作的人,请记住,如果 JRE 加载的 ScriptEngine 是 rhino(对于大多数 JDK 6 和 7 都是如此),则“importClass”有效,而在 Nashorn(从 8 开始)中,您可以使用向后兼容的“File = java.io.File”或较新但不向后兼容的 Java.type。正如我今天所经历的那样,当运行 scriptdef 出现问题时,Ant 似乎会默默地失败。 (2认同)

Jef*_*ick 15

ant-contrib是邪恶的; 编写自定义ant任务.

ant-contrib是邪恶的,因为它试图将ant从声明式转换为命令式样式.但是xml是一种废话编程语言.

相比之下,自定义ant任务允许您使用真实IDE编写真实语言(Java),您可以在其中编写单元测试以确保您拥有所需的行为,然后在构建脚本中进行干净声明你想要的行为.

如果您关心编写可维护的ant脚本,这种咆哮才有意义.如果您不关心可维护性,请做任何有效的事情.:)

JTF

  • ant-contrib真的很邪恶.现在我正处于一个大型蚂蚁构建项目的中间,该项目强烈使用if/then/else和antcalls,它真的很糟糕.整个事情看起来像一个转换的批处理/ shell脚本,并且ant所做的所有依赖项内容都被ant-contrib的大量使用完全关闭了.如果要保持设置清洁,请构建自己的任务.: - / (4认同)
  • 你是对的,我应该用Java写一个自定义的ant任务;) (2认同)
  • @cringe,我不同意.像任何东西一样,你必须知道何时使用ant-contrib符合你的最佳利益.远离像if和var之类的东西,并使用ant-contrib来避免重新发明轮子. (2认同)

dag*_*dag 5

我知道这篇文章真的很老但现在有一些时间和蚂蚁版本通过那里有一种方法来做基本的蚂蚁功能,我想我应该分享它.

它是通过一个调用嵌套任务的递归宏定义完成的(甚至可以调用其他宏).唯一的约定是使用固定的变量名称(此处为元素).

<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>
Run Code Online (Sandbox Code Playgroud)

所需的主要功能包括:

我没有设法制作分隔符变量,但这可能不是一个主要的缺点.