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}로 대상 "bar"가 호출되어 현재 파일이 생성됩니다.


그래서 내가 뭔가를 포함해야하나요? 아니면 외부 개미 라이브러리가 필요합니까? 나는군요 "문제 : 작업 또는 형식 foreach 문을 만들지 못했습니다" . 내가 올바르게 이해한다면 foreach 는 알 수없는 키워드라는 뜻 입니다.
ivan_ivanovich_ivanoff

4
Ohhh lame ... 그것은 Ant-Contrib 작업입니다. 그래서 무언가를 설치해야합니다. 여기를보십시오 : ant-contrib.sourceforge.net
blak3r

3
이 예는 ant-contrib에 포함되기 전의 foreach에서 가져온 것입니다. ant.1045680.n5.nabble.com/Using-foreach-td1354624.html에 좋은 예가 있습니다.이 예를 작동하도록 업데이트하겠습니다.
Sean

2
중첩 된 파일 세트 요소는 더 이상 사용되지 않습니다. 대신 중첩 된 경로를 사용하십시오
dude

@dude 사용 <foreach> <path> <fileset> <include name = "*. jar"/> </ fileset> </ path> </ foreach>
Sharat

88

<apply> 작업을 사용합니다 .

각 파일에 대해 한 번씩 명령을 실행합니다. 파일 세트 또는 기타 리소스를 사용하여 파일을 지정합니다. <적용>이 내장되어 있습니다. 추가 종속성이 필요하지 않습니다. 사용자 지정 작업 구현이 필요하지 않습니다.

명령을 한 번만 실행하여 한 번에 모든 파일을 인수로 추가 할 수도 있습니다. 동작을 전환하려면 parallel 속성을 사용하십시오.

1 년 늦어서 죄송합니다.


4
2011 년에이 기능이 유용하다는 것을 알았습니다. 어쨌든 감사합니다!
Michael Della Bitta 2011 년

7
<apply>의 문제점은 외부 시스템 명령 만 실행한다는 것입니다. 그것은 어떤 일도 직접하지 않을 것입니다. 그것이 원래 질문이 무엇인지 아닌지 명확하지 않습니다. 기본적으로 두 가지 상황에 대해 <apply> 또는 <foreach>를 사용해야합니다. 완전히 멍청합니다.
Archie

27

ant-contrib 없는 접근 방식 은 Tassilo Horn 이 제안합니다 ( 원래 목표는 여기에 있음 ).

Basicly의 확장자가 없기 때문에 <자바> (아직?) 같은 방법으로하는 것이 <적용> 확장 <임원> , 그 사용에 제안 <적용> (또한 명령 줄에서 자바 programm에 실행 과정의 어느 캔)

다음은 몇 가지 예입니다.

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

2
JDK8 이상에서이 작업을 시도하는 경우 JRE에서로드 한 ScriptEngine이 rhino (대부분의 JDK 6 및 7에 해당) 인 경우 "importClass"가 작동하는 반면, Nashorn (8 이후)에서는 다음을 사용할 수 있습니다. 이전 버전과 호환되는 "File = java.io.File"또는 최신 버전이지만 이전 버전과 호환되지 않는 Java.type. Ant는 오늘 경험 한 것처럼 scriptdef를 실행하는 데 문제가있을 때 조용히 실패하는 것 같습니다.
Matteo Steccolini

16

ant-contrib은 사악합니다. 사용자 지정 개미 작업을 작성합니다.

ant-contrib은 ant를 선언적 스타일에서 명령형 스타일로 변환하려고하기 때문에 악합니다. 그러나 xml은 쓰레기 프로그래밍 언어를 만듭니다.

반대로 사용자 지정 ant 작업을 사용하면 실제 IDE를 사용하여 실제 언어 (Java)로 작성할 수 있습니다. 여기서 단위 테스트를 작성하여 원하는 동작이 있는지 확인한 다음 빌드 스크립트에서 당신이 원하는 행동.

이 폭언은 유지 가능한 개미 스크립트를 작성하는 데 관심이있는 경우에만 중요합니다. 유지 관리에 대해 신경 쓰지 않는다면 작동하는 것은 무엇이든하십시오. :)

Jtf


2
END_LINK하면 관심있는 권리, 난 그냥 자바에서 사용자 지정 개미 작업을 작성해야)
ivan_ivanovich_ivanoff

4
ant-contrib은 정말 사악합니다. 지금은 if / then / else 및 antcalls를 집중적으로 사용하는 대규모 개미 빌드 프로젝트를 진행 중이며 실제로 끔찍하게 읽습니다. 모든 것이 변환 된 배치 / 쉘 스크립트처럼 보이며 ant가하는 모든 의존성 작업은 ant-contrib을 많이 사용함으로써 완전히 꺼집니다. 설정을 깨끗하게 유지하려면 고유 한 작업을 작성하십시오. : - /
굽실 거리다

2
@cringe, 동의하지 않습니다. 무엇보다도, 당신은 ant-contrib을 사용하는 것이 자신에게 가장 유익한시기를 알아야합니다. if 및 var와 같은 것을 피하고 ant-contrib을 사용하여 바퀴를 재발 명하지 않도록하십시오.
Neil

1
그리고 스크립팅 언어 였어야했고, 처음에는 선언적이 아니라 명령 적이어야했습니다. 그건 누가 IMO 악을되도록
mvmn

아마도 ant-contrib은 선험적 악이지만 black3r의 사용은 합리적이고 개미적인 것처럼 보입니다.
ssimm

7

나는이 포스트가 정말로 오래되었다는 것을 알고 있지만, 이제 약간의 시간과 개미 버전이 지나갔으므로 기본적인 개미 기능으로 이것을 할 수있는 방법이 있고 나는 그것을 공유해야한다고 생각했습니다.

중첩 된 작업을 호출하는 재귀 매크로 정의를 통해 수행됩니다 (다른 매크로도 호출 될 수 있음). 유일한 규칙은 고정 변수 이름 (여기에 요소)을 사용하는 것입니다.

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

필요한 주요 기능 :

구분자 변수를 만들지 못했지만 이것은 큰 단점이 아닐 수도 있습니다.


불행히도 이것은 메모리가 부족하고 오히려 빨리 폭발합니다.
데이비드 세인트 데니스

예, 처리하는 파일 수에 따라 스택이 날아갈 수 있습니다. 약 66 개의 파일 (메모리 옵션 증가없이)로 꽤 성공적이었습니다. 그러나 더 많은 기능을 제공하는 ant-contrib에 액세스 할 수없는 경우에만 옵션이됩니다 (예 : 병렬 실행).
dag

이것은 매우 도움이되었습니다.
DiamondDrake

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는 항아리를 저장하는 곳입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.