Java에서 명령 줄 인수를 어떻게 구문 분석합니까?


586

Java에서 명령 행 인수를 구문 분석하는 좋은 방법은 무엇입니까?


4
args4j 및 사용 방법에 대한 자세한 예를 참조하십시오. martin-thoma.com/how-to-parse-command-line-arguments-in-java
— Martin Thoma

이 파티에 꽤 늦었 던 것 같지만 Java 용 명령 줄 인수 처리기를 작성하여 GitHub에 넣었습니다 : MainArgsHandler . 스레드가 닫히는 것은 이것이 매우 유용한 스레드라고 생각하지만 일반적인 프로그래밍 토론을 위해 Stack Exchange Programmers 사이트로 마이그레이션해야 할 수도 있습니다.
— Bobulous

@RedGlyph-SO / SE가 규칙을 단순화해야하는 것처럼 보입니다. 문제는 다음과 같아야합니다 How to parse java command line arguments?. 그러나 실제로이 작업을 수행하기 위해 코드를 작성하는 대신 도구를 사용하려는 사람은 없습니다. 그러나 도구와
— 유사한

6
재개 투표. @AlikElzin : 실제로, 그들은 그들의 중재 과정을 검토해야합니다. 너무 많은 질문을 마무리 짓는 배지가 있다고 생각하며, 조정자가되기를 원하는 것은 너무 열심입니다.
— RedGlyph

8
이 질문은 잘못된 / 한 줄 답변 및 도구 권장 사항에 대한 허니팟입니다. 닫혀 있어야합니다.
— JAL

답변:


405

이것들을 확인하십시오 :

또는 자신의 롤 :


예를 들어 다음은 commons-cli2 개의 문자열 인수를 구문 분석 하는 방법입니다 .

import org.apache.commons.cli.*;

public class Main {


    public static void main(String[] args) throws Exception {

        Options options = new Options();

        Option input = new Option("i", "input", true, "input file path");
        input.setRequired(true);
        options.addOption(input);

        Option output = new Option("o", "output", true, "output file");
        output.setRequired(true);
        options.addOption(output);

        CommandLineParser parser = new DefaultParser();
        HelpFormatter formatter = new HelpFormatter();
        CommandLine cmd;

        try {
            cmd = parser.parse(options, args);
        } catch (ParseException e) {
            System.out.println(e.getMessage());
            formatter.printHelp("utility-name", options);

            System.exit(1);
        }

        String inputFilePath = cmd.getOptionValue("input");
        String outputFilePath = cmd.getOptionValue("output");

        System.out.println(inputFilePath);
        System.out.println(outputFilePath);

    }

}

명령 줄에서의 사용법 :

$> java -jar target/my-utility.jar -i asd                                                                                       
Missing required option: o

usage: utility-name
 -i,--input <arg>    input file path
 -o,--output <arg>   output file

40
다른 많은 Apache 라이브러리와 달리 Apache CLI에는 종속성이 없습니다.
— 블라디미르 듀우 예프

9
많은 아파치-커먼즈 프로젝트의 단점 중 하나는 커밋이 점점 줄어들고 결국 더 이상 사용되지 않는다는 것입니다.
— Brett Ryan

4
다음은 신속하게 사용 방법에 대해 자세히 아파치 CLI 프로젝트의 "사용 시나리오"페이지의 commons.apache.org/cli/usage.html
— 브래드 공원

인터페이스를 정의하고 메소드에 주석을 달는 것을 제외하고 Args4J / JCommander와 정확히 같은 것이 있다고 생각하지 않습니다. 개인 필드를 "초기화"하는 클래스를
— 좋아할 수 없었습니다

5
@RemkoPopma 당신의 picocli 라이브러리는 훌륭해 보이고 정말 감사합니다. 그러나 나는 당신이 여기와 다른 게시물에서하고있는 일을 고려합니다 (허용 된 답변을 편집하고 라이브러리의 게시물을 게시하지 않고 편집 한 것을 게시하지 않고 라이브러리를 홍보하지 않아도됩니다). 이것을 다른 개조에 표시합니다.
— Alexander Malakhov

312

최신 JCommander를 살펴보십시오 .

나는 그것을 만들었다. 질문이나 기능 요청을 받겠습니다.


7
JCommander를 좋아해서 기쁘다 :-) 플래그가 처리되는 방식에 너무 많은 의미를 추가하고 싶지 않았으므로 사용하는 주석에 동의어를 추가하면됩니다. @Parameter (names = { "-h", "- -help "}) 합리적인 타협이라고 생각했습니다.
— Cedric Beust

14
훌륭한 도구입니다. 강력하고 유연하며 성가신 전통적인 옵션 파서를 다룰 필요가 없습니다.
— IanGilham

3
예, JCommander를 작성한 것과 동일한 방식으로 내 명령 줄 인수 파서를 작성했을 것입니다. 훌륭한 일.
— SRG

9
@CedricBeust, 이것은 훌륭한 도서관입니다. 대단히 감사합니다. 라이브러리 클래스에 의존하지 않고 전달할 수있는 자체 Args 클래스를 정의 할 수 있으므로 매우 유연합니다.
— Brett Ryan

2
물 밖으로 경쟁을 날려 버립니다!
— 마커스 Junius Brutus

235

7
@Ben Flynn hehe, 거기에는 꽤 놀랍고 흥미로운 모양의 바퀴가 있습니다. 나는 그것을 할 수있는 여러 가지 방법이 많이 있음을 보여주는 가장 무해한 방법이라고 생각합니다!
— lexicalscope

14
JOpt Simple의 저자는 매우 비슷한 목록을 유지합니다! 텍스트가 필요한 것은 이러한 목록을 표로 바꾸어 기능과 관심 지점을 나열하는 것이므로 가난한 사용자는 정보에 입각 한 선택을 할 수 있습니다.
— Tom Anderson

1
나는 구축했습니다 (Rop)은 - github.com/ryenus/rop , 당신은 일반 클래스와 필드를 통해 명령과 옵션을 선언하는 것이 주석 기반 솔루션, 빌드 명령 줄 파서에 꽤 많이 선언적 방법을 제공합니다. Git (single-cmd) 또는 Maven (multi-cmd) 같은 앱을 빌드 할 수 있습니다.
— Ryenus

8
나열된 대부분의 프로젝트는 기본적으로 포기됩니다. 목록을 살펴본 후 적극적으로 유지 관리되고 인기가 큰 큰 타자들은 commons-cli, jcommander, args4j, jopt-simple 및 picocli로 보입니다. argparse4j 및 cli-parser와 같은 저자의 사과-나는 다소 임의의 순위를 지정해야했으며 목록에서 다른 5 가지 프로젝트를 선택했습니다. 명확하고 다른 프로젝트도 여전히 활발하게 개발 중입니다.
— George Hawkins

2
나는 누군가에게 각 파서의 마지막 안정 릴리스 날짜를 포함 시키도록 요청합니다.
— 썰매

50

그것은 Commons CLI보다 더 나은 시간을 2020입니다 ... :-)

자체 Java 명령 행 구문 분석기를 빌드하거나 라이브러리를 사용해야합니까?

많은 작은 유틸리티 유사 응용 프로그램은 추가 외부 종속성을 피하기 위해 자체 명령 행 구문 분석을 롤링 할 수 있습니다. picocli 는 흥미로운 대안이 될 수 있습니다.

Picocli는 강력하고 사용자 친화적 인 GraalVM 지원 명령 줄 앱을 쉽게 구축 할 수있는 최신 라이브러리 및 프레임 워크입니다. 하나의 소스 파일에 있으므로 앱이 종속성을 추가하지 않도록 소스로 포함시킬 수 있습니다.

색상, 자동 완성, 부속 명령 등을 지원합니다. Groovy, Kotlin, Scala 등에서 사용 가능한 Java로 작성

ANSI 색상에 대한 최소한의 사용 도움말

풍모:

  • 주석 기반 : 선언적 , 중복 방지 및 프로그래머 의도 표현
  • 편리 성 : 사용자 입력을 구문 분석하고 한 줄의 코드로 비즈니스 로직을 실행
  • 강력한 형식의 모든 것을 - 명령 줄 옵션뿐만 아니라 위치 매개 변수
  • POSIX 클러스터 된 짧은 옵션 ( <command> -xvfInputFile및 <command> -x -v -f InputFile)
  • 세밀하게 제어 : 최소, 최대 및 매개 변수의 개수를 허용하는 인수에 대응 모델, 예를 들면 "1..*","3..5"
  • 부속 명령 (임의의 깊이에 내포 될 수 있음)
  • 풍부한 기능 : 구성 가능한 arg 그룹, 인용 된 arg 분할, 반복 가능한 하위 명령 등
  • 사용자 친화적 : 사용 도움말 메시지는 색상을 사용하여 나머지 사용 도움말의 옵션 이름과 같은 중요한 요소를 대조 하여 사용자 의인지 부하 를 줄입니다.
  • 앱을 GraalVM 기본 이미지 로 배포
  • 작동 자바 5 이상
  • 광범위하고 세심한 문서

사용법 도움말 메시지는 프로그래밍없이 주석으로 쉽게 사용자 정의 할 수 있습니다. 예를 들면 다음과 같습니다.

확장 된 사용법 도움말 메시지( 소스 )

사용 도움말 메시지가 표시되는 스크린 샷을 하나 더 추가하는 것에 저항 할 수 없었습니다. 사용 도움말은 응용 프로그램의 얼굴이므로 창의적이고 재미있게 보내십시오!

피코 클리 데모

면책 조항 : 나는 picocli를 만들었습니다. 의견이나 질문은 매우 환영합니다.


5
순수한 천재! 이 답변이 바닥에 묻힌 것은 부끄러운 일입니다. Apache Commons CLI는 장황하고 버그가 많으며 오랫동안 업데이트되지 않았습니다. 명령 줄 인수 사용 내역을 기반으로 타겟팅 된 광고를 원하지 않기 때문에 Google의 CLI 파서를 사용하고 싶지 않습니다. 그러나 어쨌든 피코 클리보다 조금 더 장황하게 보입니다.
— Pete

2
나는 두 번째 @Pete ... 나는이 목록을 살펴 보았습니다.이 목록은 바닥에 묻혀있는 완전한 시간 낭비였습니다. 이것은 1 마일의 최고 답변이어야합니다. 잘 했어! Apache CLI 또는 대부분의 다른 파서에서 내 요구 사항을 처리 할 수 ​​없습니다. 그들은 picocli에게도 도전했지만, 내가 원하는 구문 / 동작에 가장 가까운 것을 줄 수 있었고 실제로 필요한 것을 해킹 할만 큼 유연했습니다. 보너스로 ANSI 기능 덕분에 멋지게 보입니다.
— Shai Almog

@ShaiAlmog 가장 인기있는 답변은 10 살이며 구식입니다. 2019 년 Commons CLI를 추천하는 것이 잘못된 IMHO라는 데 동의합니다. 고려하시기 바랍니다 재 작성 날짜에 더 만들기 위해 상단의 대답을.
— Remko Popma

나는 당신이 이미 그것을 시도했다고 생각합니다, 그게 나에게도 효과가 없을 것이라고 생각합니다 ... 1Picoli와 같은 이름을 선택했다면 알파벳 순서로 세 번째 대답을 정렬 할 수 있습니다 ;-)
— Shai Almog

변경 사항이 되돌려 진 이유는 본인이 소속을 공개하지 않았기 때문이라고 생각합니다 (저는 저자입니다). 다른 사람들에게는 그 문제가 없어야합니다.
— Remko Popma

23

JOpt를 사용하고 꽤 편리하다는 것을 알았습니다 : http://jopt-simple.sourceforge.net/

첫 페이지에는 약 8 개의 대체 라이브러리 목록이 있으며, 확인하고 필요에 가장 적합한 라이브러리를 선택하십시오.


21

누군가가 최근에 주석 기반의 args4j를 지적했습니다 . 난 정말 좋아!


1
Args4J의 경우 +1! 매우 인간 친화적이고 유연하며 이해할 수 있습니다. Java CLI 앱을 빌드하기위한 표준 이동 라이브러리이어야한다고 생각합니다.
— Zearin

JCommander가 할 수없는 정렬되지 않은 (필드 순서로 정렬 된) 사용법 인쇄를 처리 할 수 ​​있고 더 유연합니다.
— Daniel Hári 2012

@ DanielHári이 기능은 JCommander (2017 년 2 월 하순)에 추가되었습니다.
— Nathan

9

이것은 Bazel 프로젝트의 일부로 오픈 소스 된 Google의 명령 줄 구문 분석 라이브러리입니다. 개인적으로 나는 그것이 가장 훌륭하고 Apache CLI보다 훨씬 쉽다고 생각합니다.

https://github.com/pcj/google-options

설치

바젤

maven_jar(
    name = "com_github_pcj_google_options",
    artifact = "com.github.pcj:google-options:jar:1.0.0",
    sha1 = "85d54fe6771e5ff0d54827b0a3315c3e12fdd0c7",
)

그래들

dependencies {
  compile 'com.github.pcj:google-options:1.0.0'
}

메이븐

<dependency>
  <groupId>com.github.pcj</groupId>
  <artifactId>google-options</artifactId>
  <version>1.0.0</version>
</dependency>

용법

OptionsBase당신 을 확장 하고 정의 하는 클래스를 만듭니다 @Option.

package example;

import com.google.devtools.common.options.Option;
import com.google.devtools.common.options.OptionsBase;

import java.util.List;

/**
 * Command-line options definition for example server.
 */
public class ServerOptions extends OptionsBase {

  @Option(
      name = "help",
      abbrev = 'h',
      help = "Prints usage info.",
      defaultValue = "true"
    )
  public boolean help;

  @Option(
      name = "host",
      abbrev = 'o',
      help = "The server host.",
      category = "startup",
      defaultValue = ""
  )
  public String host;

  @Option(
    name = "port",
    abbrev = 'p',
    help = "The server port.",
    category = "startup",
    defaultValue = "8080"
    )
    public int port;

  @Option(
    name = "dir",
    abbrev = 'd',
    help = "Name of directory to serve static files.",
    category = "startup",
    allowMultiple = true,
    defaultValue = ""
    )
    public List<String> dirs;

}

인수를 구문 분석하고 사용하십시오.

package example;

import com.google.devtools.common.options.OptionsParser;
import java.util.Collections;

public class Server {

  public static void main(String[] args) {
    OptionsParser parser = OptionsParser.newOptionsParser(ServerOptions.class);
    parser.parseAndExitUponError(args);
    ServerOptions options = parser.getOptions(ServerOptions.class);
    if (options.host.isEmpty() || options.port < 0 || options.dirs.isEmpty()) {
      printUsage(parser);
      return;
    }

    System.out.format("Starting server at %s:%d...\n", options.host, options.port);
    for (String dirname : options.dirs) {
      System.out.format("\\--> Serving static files at <%s>\n", dirname);
    }
  }

  private static void printUsage(OptionsParser parser) {
    System.out.println("Usage: java -jar server.jar OPTIONS");
    System.out.println(parser.describeOptions(Collections.<String, String>emptyMap(),
                                              OptionsParser.HelpVerbosity.LONG));
  }

}

https://github.com/pcj/google-options


안녕 폴 답이나 프로젝트 문서를 읽을 때 어떤 종류의 명령 줄을 처리 할 수 ​​있는지 전혀 모릅니다. 예를 들어와 같은 것을 제공 할 수 있습니다 myexecutable -c file.json -d 42 --outdir ./out. 짧고 긴 / 설명 옵션을 어떻게 정의하는지
— 모르겠습니다


8

응

나는 당신이 다음과 같은 것을 찾고 있다고 생각합니다 : http://commons.apache.org/cli

Apache Commons CLI 라이브러리는 명령 행 인터페이스 처리를위한 API를 제공합니다.


7

나는 여기에있는 대부분의 사람들이 내 방식을 싫어하는 이유를 천만 가지의 이유를 발견 할 것입니다. 나는 일을 간단하게 유지하고 싶기 때문에 '='를 사용하여 키를 값과 분리하고 다음과 같이 HashMap에 저장합니다.

Map<String, String> argsMap = new HashMap<>();
for (String arg: args) {
    String[] parts = arg.split("=");
    argsMap.put(parts[0], parts[1]);
} 

사용자가 인수를 잊었거나 잘못된 인수를 사용한 경우 사용자를 돕기 위해 항상 예상 인수로 목록을 유지할 수 있습니다. 그러나 너무 많은 기능을 원할 경우이 솔루션은 어쨌든 적합하지 않습니다.


7

아마도 이것들

  • Java 용 JArgs 명령 행 옵션 구문 분석 스위트 -이 작은 프로젝트는 Java 프로그래머의 사용을 위해 편리하고 컴팩트하며 사전 패키지화되고 포괄적으로 문서화 된 명령 행 옵션 구문 분석기 스위트를 제공합니다. 처음에는 GNU 스타일 'getopt'와 호환되는 구문 분석이 제공됩니다.

  • ritopt, Java 용 Ultimate Options Parser- 여러 명령 행 옵션 표준이 제안되었지만 ritopt는 opt 패키지에 규정 된 규칙을 따릅니다.






4

이미 Spring Boot를 사용하고 있다면 인수 구문 분석이 즉시 제공됩니다.

시작 후 무언가를 실행하려면 ApplicationRunner인터페이스를 구현하십시오 .

@SpringBootApplication
public class Application implements ApplicationRunner {

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }

  @Override
  public void run(ApplicationArguments args) {
    args.containsOption("my-flag-option"); // test if --my-flag-option was set
    args.getOptionValues("my-option");     // returns values of --my-option=value1 --my-option=value2 
    args.getOptionNames();                 // returns a list of all available options
    // do something with your args
  }
}

귀하의 run문맥이 성공적으로 시작한 후에 방법은 호출됩니다.

응용 프로그램 컨텍스트를 시작 하기 전에 인수에 액세스해야하는 경우 응용 프로그램 인수를 수동으로 구문 분석하면됩니다.

@SpringBootApplication
public class Application implements ApplicationRunner {

  public static void main(String[] args) {
    ApplicationArguments arguments = new DefaultApplicationArguments(args);
    // do whatever you like with your arguments
    // see above ...
    SpringApplication.run(Application.class, args);
  }

}

마지막으로 빈에서 인수에 액세스 해야하는 경우 ApplicationArguments:

@Component
public class MyBean {

   @Autowired
   private ApplicationArguments arguments;

   // ...
}

대단합니다 :).
— John Humphreys-

3

내가 찾은 것이 Argparse4j가 최고입니다. 그것은 매우 편리하고 강력한 파이썬의 argparse 라이브러리를 모방합니다.


2

가볍고 (jar size ~ 20 kb) 사용하기 쉬운 것을 원한다면 argument-parser를 사용해보십시오 . 대부분의 유스 케이스에서 사용할 수 있으며 인수에서 배열 지정을 지원하며 다른 라이브러리에 종속되지 않습니다. Java 1.5 이상에서 작동합니다. 아래 발췌문은 그것을 사용하는 방법에 대한 예를 보여줍니다.

public static void main(String[] args) {
    String usage = "--day|-d day --mon|-m month [--year|-y year][--dir|-ds directoriesToSearch]";
    ArgumentParser argParser = new ArgumentParser(usage, InputData.class);
    InputData inputData = (InputData) argParser.parse(args);
    showData(inputData);

    new StatsGenerator().generateStats(inputData);
}

더 많은 예제는 여기 에서 찾을 수 있습니다


1
연결이 끊어졌습니다. 프로젝트를 죽였습니까? :-(
— beldaz

2

Apache Common CLI스레드 안전하지 않기 때문에 라이브러리를 사용하지 않는 것이 좋습니다 .

정적 변수 및 메소드와 함께 상태 저장 클래스를 사용하여 내부 작업 (예 :)을 수행 OptionBuilder하며 단일 스레드 강력하게 제어되는 상황에서만 사용해야합니다.


18
CLI 라이브러리는 스레드로부터 안전하지 않습니다. 그러나 명령 줄 구문 분석은 일반적으로 응용 프로그램 시작 중 단일 스레드에서 수행되며 매개 변수에 따라 다른 스레드가 시작될 수 있다고 가정합니다.
— Alexey Ivanov

0

앞에서 언급 한 의견 중 하나 ( https://github.com/pcj/google-options )를 시작하는 것이 좋습니다.

내가 추가하고 싶은 한 가지는 :

1) 파서 반영 오류가 발생하면 최신 버전의 구아바를 사용해보십시오. 나의 경우에는:

maven_jar(
    name = "com_google_guava_guava",
    artifact = "com.google.guava:guava:19.0",
    server = "maven2_server",
)

maven_jar(
    name = "com_github_pcj_google_options",
    artifact = "com.github.pcj:google-options:jar:1.0.0",
    server = "maven2_server",
)

maven_server(
    name = "maven2_server",
    url = "http://central.maven.org/maven2/",
)

2) 명령 줄을 실행할 때 :

bazel run path/to/your:project -- --var1 something --var2 something -v something

3) 사용법 도움말이 필요하면 다음을 입력하십시오.

bazel run path/to/your:project -- --help

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