Làm cách nào để phân tích các đối số dòng lệnh trong Java?


586

Một cách tốt để phân tích các đối số dòng lệnh trong Java là gì?


4
Xem args4j và một ví dụ chi tiết về cách sử dụng nó: martin-thoma.com/how-to-parse-command-line-argument-in-java
Martin Thoma

Có vẻ như tôi đến khá muộn cho bữa tiệc này, nhưng tôi đã viết một trình xử lý đối số dòng lệnh cho Java và đưa nó lên GitHub: MainArgsHandler . Đối với luồng được đóng, tôi nghĩ rằng đây là một luồng rất hữu ích, nhưng nó có thể nên được di chuyển đến trang web Stack Exchange Lập trình viên để thảo luận về lập trình chung.
Bobious

@RedGlyph - Có vẻ như SO / SE cần đơn giản hóa các quy tắc của họ. Câu hỏi nên có : How to parse java command line arguments?. Nhưng không ai thực sự muốn viết mã để làm điều này mà chỉ sử dụng một công cụ. Nhưng tìm kiếm các công cụ và những thứ tương tự không mang tính xây dựng :(
AlikElzin-kilaka

6
Bình chọn để mở lại. @AlikElzin: Thật vậy, họ cần xem lại quy trình kiểm duyệt của mình. Tôi nghi ngờ có một huy hiệu để đóng rất nhiều câu hỏi và rằng nó muốn thu hút những người điều hành muốn quá nhiệt tình.
RedGlyph

8
Câu hỏi này là một honeypot cho câu trả lời xấu / một dòng và đề xuất công cụ. Nó sẽ vẫn đóng cửa.
JAL

Câu trả lời:


405

Kiểm tra những điều này:

Hoặc tự cuộn:


Chẳng hạn, đây là cách bạn sử dụng commons-cliđể phân tích 2 đối số chuỗi:

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

    }

}

sử dụng từ dòng lệnh:

$> 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
Lưu ý rằng không giống như nhiều thư viện Apache khác, Apache CLI không có phụ thuộc.
Vladimir Dyuzhev

9
Một nhược điểm của nhiều dự án apache-commons là chúng ngày càng ít cam kết hơn và cuối cùng bị lỗi thời.
Brett Ryan

4
Đây là trang "Kịch bản sử dụng" cho dự án Apache CLI, chi tiết cách bắt đầu nhanh chóng sử dụng nó: commons.apache.org/cli/usage.html
Brad park

Tôi không cho rằng có một cái giống hệt như Args4J / JCommander ngoại trừ nơi bạn xác định giao diện và chú thích các phương thức? Tôi chưa bao giờ có thể phát triển yêu thích các lớp học "khởi tạo ma quái" các lĩnh vực tư nhân ...
Trejkaz

5
@RemkoPopma thư viện picocli của bạn trông thật tuyệt và cảm ơn bạn đã làm nó, thực sự. Nhưng tôi xem xét những gì bạn đang làm ở đây và trong các bài đăng khác (chỉnh sửa câu trả lời được chấp nhận và quảng bá thư viện của bạn ở đầu trang mà không tiết lộ đó là bản chỉnh sửa không phải từ tác giả gốc của bài đăng và đó là lib của bạn) một sự lạm dụng khủng khiếp đối với quyền hạn kiểm duyệt của bạn. Gắn cờ này cho các mod khác.
Alexander Malakhov

312

Hãy xem JCommander gần đây hơn .

Tôi đã tạo ra nó. Tôi rất vui khi nhận được câu hỏi hoặc yêu cầu tính năng.


7
Rất vui khi bạn thích JCommander :-) Tôi không muốn thêm quá nhiều ngữ nghĩa vào cách xử lý các cờ, vì vậy bạn chỉ cần thêm từ đồng nghĩa trong các chú thích bạn sử dụng: @Parameter (tên = {"-h", "- -help "}) Tôi nghĩ đó là một sự thỏa hiệp hợp lý.
Cedric Beust

14
Công cụ tuyệt vời. Mạnh mẽ, linh hoạt và bạn không phải đối phó với các trình phân tích cú pháp tùy chọn truyền thống gây phiền nhiễu.
IanGilham

3
Vâng, tôi nghĩ rằng tôi đã viết trình phân tích cú pháp đối số dòng lệnh của riêng tôi giống như cách bạn đã viết JCommander. Công việc tuyệt vời
SRG

9
@CedricBeust, đây là một thư viện tuyệt vời, tôi cảm ơn bạn rất nhiều. Vì chúng ta có thể định nghĩa các lớp Args của riêng mình mà sau đó có thể được truyền qua mà không phụ thuộc vào lớp thư viện, nó làm cho nó cực kỳ linh hoạt.
Brett Ryan

2
thổi sự cạnh tranh ra khỏi nước!
Marcus Junius Brutus

235

7
@Ben Flynn hehe, có một số bánh xe có hình dạng khá bất ngờ và thú vị ở đó. Tôi đoán đó là một cách vô hại để cho thấy rằng có nhiều hơn một cách để làm điều đó!
vựng

14
Tôi lưu ý tác giả của JOpt Simple duy trì một danh sách rất giống nhau! Những gì chúng ta cần văn bản là để biến các danh sách này thành một bảng, liệt kê các tính năng và các điểm quan tâm, vì vậy chúng tôi người dùng nghèo có thể đưa ra lựa chọn sáng suốt.
Tom Anderson

1
Tôi đã xây dựng Rop - github.com/ryenus/rop , có tính năng giải pháp dựa trên chú thích mà bạn khai báo các lệnh và tùy chọn thông qua các lớp và trường đơn giản, gần như là một cách khai báo để xây dựng trình phân tích cú pháp dòng lệnh. nó có thể xây dựng các ứng dụng như Git (đơn cmd) hoặc Maven (đa cmd).
ryenus

8
Hầu hết các dự án được liệt kê về cơ bản là từ bỏ. Sau khi xem qua danh sách, tôi muốn nói rằng những người đại gia, được duy trì tích cực và phổ biến, dường như là commons-cli, jcommander, args4j, jopt-Simple và picocli. Xin lỗi các tác giả của những thứ như argparse4j và cli-Parser - Tôi đã phải xếp hạng hơi độc đoán và chọn một năm dự án hàng đầu, rõ ràng các dự án khác trong danh sách là phổ biến và vẫn đang được phát triển tích cực.
George Hawkins

2
Tôi thách thức ai đó bao gồm ngày phát hành ổn định cuối cùng của mỗi trình phân tích cú pháp.
Sledge

50

Đó là năm 2020, thời gian để làm tốt hơn Commons CLI ... :-)

Bạn nên xây dựng trình phân tích cú pháp dòng lệnh Java của riêng bạn hay sử dụng một thư viện?

Nhiều ứng dụng nhỏ giống như tiện ích có thể cuộn phân tích dòng lệnh của riêng chúng để tránh phụ thuộc bên ngoài. picocli có thể là một thay thế thú vị.

Picocli là một thư viện và khung hiện đại để xây dựng các ứng dụng dòng lệnh mạnh mẽ, thân thiện với người dùng, hỗ trợ GraalVM một cách dễ dàng. Nó nằm trong 1 tệp nguồn nên các ứng dụng có thể bao gồm nó dưới dạng nguồn để tránh thêm phụ thuộc.

Nó hỗ trợ màu sắc, tự động hoàn thành, các tiểu ban, v.v. Được viết bằng Java, có thể sử dụng từ Groovy, Kotlin, Scala, v.v.

Trợ giúp sử dụng tối thiểu với màu ANSI

Đặc trưng:

  • Chú thích dựa trên: khai báo , tránh trùng lặpthể hiện ý định lập trình viên
  • Thuận tiện: phân tích cú pháp người dùng nhập và chạy logic kinh doanh của bạn với một dòng mã
  • Gõ mạnh mọi thứ - tùy chọn dòng lệnh cũng như các tham số vị trí
  • POSIX cụm tùy chọn ngắn ( <command> -xvfInputFilecũng như <command> -x -v -f InputFile)
  • Kiểm soát chi tiết : một mô hình arity cho phép số lượng tham số tối thiểu, tối đa và thay đổi, ví dụ "1..*","3..5"
  • Các tiểu ban (có thể được lồng vào độ sâu tùy ý)
  • Giàu tính năng : các nhóm đối số có thể tổng hợp, tách các đối số được trích dẫn, các tiểu ban lặp lại và nhiều hơn nữa
  • Thân thiện với người dùng : thông báo trợ giúp sử dụng sử dụng màu sắc để tương phản các yếu tố quan trọng như tên tùy chọn từ phần còn lại của việc sử dụng giúp giảm tải nhận thức cho người dùng
  • Phân phối ứng dụng của bạn dưới dạng hình ảnh gốc GraalVM
  • Hoạt động với Java 5 trở lên
  • Tài liệu mở rộng và tỉ mỉ

Thông báo trợ giúp sử dụng dễ dàng tùy chỉnh với các chú thích (không cần lập trình). Ví dụ:

Thông báo trợ giúp sử dụng mở rộng( nguồn )

Tôi không thể cưỡng lại việc thêm một ảnh chụp màn hình để hiển thị những thông báo trợ giúp sử dụng nào có thể. Trợ giúp sử dụng là bộ mặt của ứng dụng của bạn, vì vậy hãy sáng tạo và vui chơi!

demo picocli

Disclaimer: Tôi đã tạo picocli. Phản hồi hoặc câu hỏi rất hoan nghênh.


5
Thiên tài thuần túy! Thật xấu hổ khi câu trả lời này bị chôn vùi dưới đáy. Apache Commons CLI dài dòng, lỗi và không được cập nhật trong một thời gian dài. Và tôi không muốn sử dụng trình phân tích cú pháp CLI của Google vì tôi không muốn quảng cáo được nhắm mục tiêu dựa trên lịch sử sử dụng đối số dòng lệnh của mình. Nhưng dù sao nó cũng có vẻ dài dòng hơn picocli một chút.
Pete

2
Tôi thứ hai @Pete ở đây ... Tôi đã xem qua danh sách trên đây là một sự lãng phí hoàn toàn thời gian với việc chôn vùi ở phía dưới. Đây phải là câu trả lời hàng đầu bởi một dặm. Bạn đã làm rất tốt! Yêu cầu của tôi không thể được bao phủ bởi CLI apache hoặc hầu hết các trình phân tích cú pháp khác. Chúng đã thách thức ngay cả đối với picocli nhưng nó có thể mang lại cho tôi điều gần gũi nhất với cú pháp / hành vi tôi muốn và đủ linh hoạt để hack theo những gì tôi thực sự cần. Như một phần thưởng, nó trông tuyệt vời nhờ vào công cụ ANSI.
Shai Almog

@ShaiAlmog Câu trả lời được bình chọn hàng đầu là 10 năm và lỗi thời. Tôi đồng ý rằng việc giới thiệu Commons CLI vào năm 2019 là IMHO gây hiểu lầm. Vui lòng xem xét viết lại câu trả lời hàng đầu để làm cho nó cập nhật hơn.
Remko Popma

Tôi thấy bạn đã thử điều đó, tôi cũng không nghĩ rằng nó sẽ hiệu quả với tôi ... Nếu bạn đã chọn một cái tên như 1Picoli, chúng tôi có thể sắp xếp câu trả lời thứ 3 theo thứ tự abc ;-)
Shai Almog

Tôi nghĩ lý do thay đổi của tôi được hoàn nguyên là vì tôi đã không tiết lộ mối liên hệ của mình (rằng tôi là tác giả). Những người khác không nên có vấn đề đó.
Remko Popma

23

Tôi đã sử dụng JOpt và thấy nó khá tiện dụng: http://jopt-simple.sourceforge.net/

Trang đầu cũng cung cấp một danh sách khoảng 8 thư viện thay thế, kiểm tra chúng và chọn một thư viện phù hợp nhất với nhu cầu của bạn.


21

Một số người chỉ cho tôi đến args4j gần đây là chú thích dựa trên. Tôi thực sự thích nó!


1
+1 cho Args4J! Vô cùng thân thiện với con người, linh hoạt và dễ hiểu. Tôi nghĩ rằng nó phải là thư viện chuyển tiếp tiêu chuẩn để xây dựng các ứng dụng Java CLI.
Zearin

Thật tuyệt khi nó có thể xử lý bản in sử dụng không được sắp xếp (sắp xếp theo thứ tự trường), mà JCommander không thể, và nó linh hoạt hơn.
Daniel Hári

@ DanielHári Chỉ để biết thông tin, chức năng này đã được thêm vào JCommander (đôi khi vào cuối tháng 2 năm 2017).
Nathan

9

Đây là thư viện phân tích cú pháp dòng lệnh của Google có nguồn mở như một phần của dự án Bazel. Cá nhân tôi nghĩ rằng đó là thứ tốt nhất ngoài kia, và dễ dàng hơn nhiều so với Apache CLI.

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

Cài đặt

Bazel

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

Học sinh lớp

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

Maven

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

Sử dụng

Tạo một lớp mở rộng OptionsBasevà định nghĩa @Option(các) của bạn .

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;

}

Phân tích các đối số và sử dụng chúng.

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


Chào Paul. Khi tôi đọc câu trả lời của bạn hoặc tài liệu dự án của bạn, tôi không biết nó có thể xử lý loại dòng lệnh nào. Ví dụ, bạn có thể cung cấp một cái gì đó như myexecutable -c file.json -d 42 --outdir ./out. Và tôi không thấy cách bạn xác định các tùy chọn ngắn / dài / mô tả ... Chúc mừng
olibre



7

Tôi biết hầu hết mọi người ở đây sẽ tìm thấy 10 triệu lý do tại sao họ không thích cách của tôi, nhưng không bao giờ. Tôi muốn giữ mọi thứ đơn giản, vì vậy tôi chỉ tách khóa khỏi giá trị bằng cách sử dụng '=' và lưu trữ chúng trong HashMap như thế này:

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

Bạn luôn có thể duy trì một danh sách với các đối số bạn đang mong đợi, để giúp người dùng trong trường hợp anh ta quên một đối số hoặc sử dụng một đối số sai ... Tuy nhiên, nếu bạn muốn quá nhiều tính năng thì giải pháp này không dành cho bạn.


7

Có lẽ những


6

Bạn có thể thấy bài báo meta về sự bất hạnh này thú vị như một điểm xuất phát:

http://fquilpurpose.blogspot.com/2008/07/command-line-parsing-lologists-for-java.html


2
Anh chàng đó khá vô dụng "Commons CLI Rõ ràng là lựa chọn lâu đời nhất ở đây, và không nhận được nhiều sự tôn trọng từ các nhà bình luận, vì vậy tôi đã không thực sự xem xét điều này rất chặt chẽ ..", nhưng dù sao cũng cảm ơn vì liên kết.
James McMahon




4

Nếu bạn đã sử dụng Spring Boot, phân tích cú pháp đối số sẽ xuất hiện.

Nếu bạn muốn chạy một cái gì đó sau khi khởi động, hãy thực hiện ApplicationRunnergiao diện:

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

runPhương pháp của bạn sẽ được gọi sau khi bối cảnh đã khởi động thành công.

Nếu bạn cần truy cập vào các đối số trước khi kích hoạt bối cảnh ứng dụng của mình, bạn chỉ cần phân tích cú pháp các đối số ứng dụng theo cách thủ công:

@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);
  }

}

Và cuối cùng, nếu bạn cần quyền truy cập vào các đối số của mình trong một bean, chỉ cần thêm ApplicationArguments:

@Component
public class MyBean {

   @Autowired
   private ApplicationArguments arguments;

   // ...
}

Điều này thật tuyệt :).
John Humphreys - w00te

3

Argparse4j là tốt nhất tôi đã tìm thấy. Nó bắt chước ngôn ngữ lập luận của Python rất tiện lợi và mạnh mẽ.


2

Nếu bạn muốn một cái gì đó nhẹ (kích thước jar ~ 20 kb) và đơn giản để sử dụng, bạn có thể thử trình phân tích cú pháp đối số . Nó có thể được sử dụng trong hầu hết các trường hợp sử dụng, hỗ trợ chỉ định mảng trong đối số và không phụ thuộc vào bất kỳ thư viện nào khác. Nó hoạt động cho Java 1.5 trở lên. Đoạn trích dưới đây cho thấy một ví dụ về cách sử dụng nó:

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);
}

Thêm ví dụ có thể được tìm thấy ở đây


1
Liên kết đã chết. Bạn đã giết chết dự án của bạn? :-(
beldaz

2

Tôi không khuyên bạn nên sử dụng Apache Common CLIthư viện, vì nó không an toàn.

Nó sử dụng các lớp trạng thái với các biến và phương thức tĩnh để thực hiện công việc nội bộ (ví dụ OptionBuilder) và chỉ nên được sử dụng trong các tình huống được kiểm soát mạnh mẽ đơn luồng.


18
Hãy nhớ rằng thư viện CLI không an toàn cho chuỗi. Tuy nhiên, tôi cho rằng việc phân tích cú pháp dòng lệnh thường được thực hiện trong một luồng trong khi khởi động ứng dụng, và sau đó, tùy thuộc vào tham số, các luồng khác có thể được khởi động.
Alexey Ivanov

0

Là một trong những ý kiến ​​được đề cập trước đó ( https://github.com/pcj/google-options ) sẽ là một lựa chọn tốt để bắt đầu.

Một điều tôi muốn thêm vào là:

1) Nếu bạn gặp phải một số lỗi phản ánh của trình phân tích cú pháp, vui lòng thử sử dụng phiên bản mới hơn của ổi. trong trường hợp của tôi:

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) Khi chạy dòng lệnh:

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

3) Khi bạn cần trợ giúp sử dụng, chỉ cần gõ:

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

-1

Đối với người dùng Spring, chúng tôi cũng nên đề cập https://docs.spring.io/spring/docs/civerse/javadoc-api/org/springframework/core/env/SimpleCommandLinePropertySource.html và anh em sinh đôi của mình https: //docs.spring .io / mùa xuân / docs / hiện tại / javadoc-api / org / spring Framework / lõi / env / JOptCommandLinePropertySource.html (JOpt thực hiện chức năng tương tự). Ưu điểm trong Spring là bạn có thể liên kết trực tiếp các đối số dòng lệnh với các thuộc tính, có một ví dụ ở đây https://docs.spring.io/spring/docs/civerse/javadoc-api/org/springframework/core/env/ CommandLinePropertySource.html

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.