Ant:ディレクトリ内の各ファイルに対してコマンドを実行する方法は?


97

ディレクトリ内の各ファイルに対して、Antビルドファイルからコマンドを実行したい。
プラットフォームに依存しないソリューションを探しています。

どうすればよいですか?

もちろん、スクリプト言語でスクリプトを書くこともできますが、これによりプロジェクトにさらに依存関係が追加されます。

回答:


61

短い答え

<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}で呼び出され、現在のファイルが生成されます。


だから、私は何かを含める必要がありますか?または、外部のant libが必要ですか?私は取得しています「問題:タスクまたはタイプのforeachの作成に失敗しました」。私が正しく理解していれば、これはforeachが不明なキーワードであることを意味します。
ivan_ivanovich_ivanoff

4
ああラメ…それはAnt-Contribタスクです。したがって、何かをインストールする必要があります。ここを参照してください:ant-contrib.sourceforge.net
blak3r

3
その例は、ant-contribに含まれる前のforeachからのものです。ant.1045680.n5.nabble.com/Using-foreach-td1354624.htmlに良い例があります。この例を更新して機能させます。
Sean

2
ネストされたファイルセット要素は廃止されました。代わりにネストされたパスを使用してください
デュード

@dude <foreach> <path> <fileset> <include name = "*。jar" /> </ fileset> </ path> </ foreach>を使用
Sharat

88

<apply>タスクを使用します

ファイルごとにコマンドを1回実行します。ファイルセットまたはその他のリソースを使用してファイルを指定します。<apply>は組み込みです。追加の依存関係は必要ありません。カスタムタスクの実装は必要ありません。

コマンドを一度だけ実行して、すべてのファイルを引数として一度に追加することもできます。動作を切り替えるには、parallel属性を使用します。

一年遅れてすみません。


4
まあ私はこれが2011年に便利だと思ったので、とにかくそれをありがとう!
マイケルデラビッタ2011年

7
<apply>の問題は、外部システムコマンドのみを実行することです。それは直接なんらかのことをしません。それが最初の質問がそうであったかどうかがはっきりしない。基本的に、2つの異なる状況に対して<apply>または<foreach>を使用する必要があります。
Archie

27

ant-contribを使用しないアプローチはTassilo Hornによって提案されています(元のターゲットはここにあります

<app ><exec>を拡張するのと同じ方法で(まだ?)<java>の拡張はないため、基本的に<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> 

2
元の質問では明らかに必要でしたが、これはプラットフォームにあまり依存していません...
チャッキー

18

これは、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>

project上記の例では変数が参照されていますが、事前の定義はありません。それを表現したり、明確にしたりするとよいでしょう。編集:n / m、project現在のプロジェクトにアクセスするための事前定義の変数であることがわかりました。私はそれを疑っていたが、確信が持てなかった。
Jon L.

1
JDK8以降でこれを試す場合、JREによってロードされたScriptEngineがrhino(ほとんどのJDK 6および7に当てはまる)である場合に「importClass」が機能することに注意してください。Nashorn(8以降)では、下位互換性のある「File = java.io.File」またはそれより新しいが下位互換性のないJava.type。今日私が経験したように、scriptdefの実行に問題があると、Antは静かに失敗するようです。
Matteo Steccolini、

15

ant-contribは悪です。カスタムantタスクを記述します。

ant-contribは、antを宣言型スタイルから命令型スタイルに変換しようとするため、悪です。しかし、xmlは粗末なプログラミング言語を作ります。

対照的に、カスタムantタスクを使用すると、実際のIDEを使用して実際の言語(Java)で記述できるため、ユニットテストを記述して必要な動作を確認し、ビルドスクリプトで明確な宣言を行うことができます。あなたが望む行動。

これは、保守可能なAntスクリプトを作成することに関心がある場合にのみ重要です。メンテナンス性を気にしないのであれば、何でもうまくいきます。:)

JTF


2
そうです、Javaでカスタムantタスクを作成するだけです;)
ivan_ivanovich_ivanoff

4
ant-contribは本当に悪です。現在、私はif / then / elseとantcallsを集中的に使用する大規模なantビルドプロジェクトの真っ最中です。全体は変換されたバッチ/シェルスクリプトのように見え、antが行うすべての依存関係は、ant-contribの多用により完全に無効になります。セットアップをクリーンに保ちたい場合は、独自のタスクを作成してください。:-/
2010

2
@cringe、私は同意しません。何でもそうですが、ant-contribを使用することがいつになるかを知る必要があります。ifやvarなどを避け、ant-contribを使用して、ホイールを作り直す必要がないようにします。
Neil、

1
そもそもスクリプト言語である必要があり、そもそも命令的で宣言的ではないはずです。だから、それは誰が邪悪なIMOなのか
mvmn 2012年

多分、ant-contribはアプリオリの悪ですが、black3rのそれの使用は、いわば合理的で、ant-ishのようです。
ssimm 2017

7

私はこの投稿が本当に古いことを知っていますが、いくつかの時間とantバージョンが渡されたので、基本的なant機能でこれを行う方法があり、共有する必要があると思いました。

ネストされたタスクを呼び出す再帰的なmacrodefを介して行われます(他のマクロも呼び出される可能性があります)。唯一の規則は、固定変数名(ここでは要素)を使用することです。

<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>

必要な主な機能:

私はなんとかデリミタを可変にできませんでしたが、これは大きな欠点ではないかもしれません。


残念ながら、これはメモリが不足し、かなり速く爆発します。
David St Denis 2014年

はい、処理するファイルの数によっては、スタックが爆発する可能性があります。私はそれを約66ファイルでかなり成功させました(メモリオプションを増やすことなく)。ただし、ant-contribにアクセスできない場合にのみオプションが提供され、より多くの機能が提供されます(たとえば、並列実行)。
2014年

これはとても役に立ちました。
DiamondDrake 2018

0

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>

0

blak3rが提案したことを行い、ターゲットのクラスパスをそのように定義します

<taskdef resource="net/sf/antcontrib/antlib.xml">
    <classpath>
        <fileset dir="lib">
          <include name="**/*.jar"/>
        </fileset>
    </classpath>        
</taskdef>

libはjarを保存する場所です。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.