Каков хороший способ анализа аргументов командной строки в Java?
Похоже, я довольно поздно пришел на эту вечеринку, но я написал обработчик аргументов командной строки для Java и поместил его на GitHub: MainArgsHandler. Что касается закрываемого потока, я думаю, что это очень полезный поток, но его, возможно, следует перенести на сайт Stack Exchange Programmers для общего обсуждения программирования.
@RedGlyph - Похоже, SO / SE нужно упростить свои правила. Вопрос должен был быть: How to parse java command line arguments?. Но на самом деле никто не хочет писать код для этого, а скорее использует инструмент. Но поиск инструментов и тому подобного неконструктивен :(
Проголосовали за открытие. @AlikElzin: Действительно, им нужно пересмотреть свой процесс модерации. Я подозреваю, что есть значок, позволяющий закрыть так много вопросов, и что он заманивает желающих быть модераторами чрезмерным усердием.
Этот вопрос - приманка для плохих / однострочных ответов и рекомендаций по инструментам. Он должен оставаться закрытым.
Вы также можете найти библиотеки, помеченные как «Парсеры командной строки» в mvnrepository.com
Я бы не рекомендовал использовать библиотеку Apache Common CLI, так как она не является потокобезопасной. Он использует классы с отслеживанием состояния со статическими переменными и методами для выполнения внутренней работы (например, OptionBuilder) и должен использоваться только в однопоточных строго контролируемых ситуациях.
Следует иметь в виду, что библиотека CLI не является потокобезопасной. Однако я предполагаю, что синтаксический анализ командной строки обычно выполняется в одном потоке во время запуска приложения, а затем, в зависимости от параметров, могут запускаться другие потоки.




Проверьте это:
Или сверните свой собственный:
Например, вот как вы используете commons-cli для синтаксического анализа 2 строковых аргументов:
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
Обратите внимание, что в отличие от многих других библиотек Apache, Apache CLI не имеет зависимостей.
Единственным недостатком многих проектов apache-commons является то, что они получают все меньше и меньше коммитов и в конечном итоге становятся устаревшими.
Вот страница «Сценарии использования» проекта Apache CLI, на которой подробно описано, как быстро начать его использовать: commons.apache.org/cli/usage.html
Я не думаю, что есть такой, как Args4J / JCommander, за исключением того, где вы определяете интерфейс и аннотируете методы? Мне никогда не удавалось полюбить классы, которые "жутко инициализируют" частные поля ...
@CedricBeust Не поддерживает аргументы стиля --variable=value?
@BrettRyan - это дело каждого в сообществе, чтобы проекты Apache оставались живыми. Открыть исходный код непросто, здесь нужна деревня, другие штампы, пожалуйста.
@RemkoPopma, ваша библиотека picocli выглядит просто великолепно, и спасибо вам за это, правда. Но я считаю то, что вы делаете здесь и в других сообщениях (редактируйте принятые ответы и продвигайте свою библиотеку наверху, даже не раскрывая, что это редактирование не от исходного автора сообщения, а ваша библиотека), ужасным ужасным злоупотреблением вашими полномочиями модератора. Пометка этого в других модах.
@AlexanderMalakhov Я хочу исправить одну вещь: кто-нибудь может редактировать (полномочия модерации не требуются), а редактирование - поощряется, чтобы сообщения оставались актуальными и актуальными (текущий ответ - 10 лет). Тем не менее, хорошие правки должны быть сбалансированы, чтобы не считаться спамом, и должны раскрывать принадлежность. Спасибо, что указали на это.
Взгляните на проект Commons CLI, там много хороших вещей.
Может, эти
Разбор параметров командной строки JArgs набор для Java - этот крошечный проект предоставляет удобный, компактный, предварительно упакованный и всесторонне документированный набор парсеров параметров командной строки для использования программистами Java. Изначально предоставляется синтаксический анализ, совместимый с «getopt» в стиле GNU.
ritopt, Парсер Ultimate Options для Java - Хотя было предложено несколько стандартов параметров командной строки, ritopt следует соглашениям, предписанным в пакете opt.
Я использовал JOpt, и он мне очень пригодился: http://jopt-simple.sourceforge.net/
На главной странице также представлен список из примерно 8 альтернативных библиотек, просмотрите их и выберите ту, которая больше всего соответствует вашим потребностям.
Ага.
Я думаю, вы ищете что-то вроде этого: http://commons.apache.org/cli
The Apache Commons CLI library provides an API for processing command line interfaces.
Если вы знакомы с gnu getopt, порт Java находится по адресу: http://www.urbanophile.com/arenn/hacking/download.htm.
Кажется, есть несколько классов, которые делают это:
Кто-то недавно указал мне на args4j, который основан на аннотациях. Мне это и вправду нравится!
+1 для Args4J! Чрезвычайно дружелюбный, гибкий и понятный. Я думаю, что это должна быть стандартная библиотека для создания приложений Java CLI.
Замечательно, что он может обрабатывать неупорядоченную (отсортированную по порядку полей) печать использования, чего не может JCommander, и более гибкий.
@ DanielHári Для информации, эта функция была добавлена в JCommander (где-то в конце февраля 2017 года).
Взгляните на более свежий JCommander.
Я создал это. Я буду рад получить вопросы или пожелания.
Использую сейчас и люблю это! Я хотел бы видеть автоматический синтаксический анализ аргументов - и - для аргументов типа single char vs string. т.е. «h» против «-h» и «help» против «--help»
Рад, что вам нравится JCommander :-) Я не хотел добавлять слишком много семантики в то, как обрабатываются флаги, поэтому вам просто нужно добавить синонимы в аннотации, которые вы используете: @Parameter (names = {"-h", "- -help "}) Я подумал, что это разумный компромисс.
Отличный инструмент. Мощный, гибкий, и вам не придется иметь дело с надоедливыми традиционными синтаксическими анализаторами параметров.
Да, думаю, я бы написал свой собственный синтаксический анализатор аргументов командной строки точно так же, как вы написали JCommander. Отличная работа.
@CedricBeust, это замечательная библиотека, большое спасибо. Поскольку мы можем определять наши собственные классы Args, которые затем можно передавать без какой-либо зависимости от класса библиотек, это делает его чрезвычайно гибким.
выдувает конкурентов из воды!
Нравится библиотека, но стоит обновить ссылку! Некоторые ссылки в нем не работают (например, Javadocs).
Я новичок в Java, но все же этот пакет настолько прост в использовании и работает как шарм. Отличный пакет
Обратной стороной является то, что у него нет автоматической генерации справочного сообщения :(
@Qix: Это действительно так: просто вызовите метод usage() в своем объекте JCommander, и вы увидите экран справки со всеми вашими параметрами и их описанием.
Отличный инструмент, но он не может обрабатывать неупорядоченную справку по использованию (которая должна быть упорядочена по порядку полей), поэтому я использую args4j вместо.
@ DanielHári Я готов добавить это в JCommander, хотя, поскольку порядок полей не может быть надежно проанализирован, это, вероятно, будет целочисленным атрибутом в аннотации @Parameter.
@CedricBeust Почему нельзя достоверно проанализировать? Другие библиотеки могут определять порядок полей по умолчанию и без целочисленного параметра. См .: JAXB, Gson, Args4j и т. д.
Я имею в виду, что то, что вы перечисляете свои поля в определенном порядке в своем классе, не означает, что API интроспекции вернет их в этом порядке. Вам нужно будет указать их вручную с аннотацией. Я могу добавить это, не стесняйтесь сообщать о проблеме на github.
Я только что выпустил новый JCommander, который позволяет вам упорядочивать параметры в usage (): jcommander.org/#_usage
Мне нравится JCommander. Возможно ли иметь только аннотацию уровня класса (указать стиль CLI), чтобы избежать всех аннотаций в каждом поле, как это делает lombok?
Поддерживает ли он подпрограммы / подпарсеры? Хотелось бы, чтобы аргументы в пользу myprog foo ... были разные, а в пользу myprog bar были разные. Является ли это возможным?
Я пытался поддерживать список парсеров Java CLI.
@ Бен Флинн хе-хе, там есть несколько довольно удивительных и интересных колес. Думаю, это в основном безобидный способ показать, что есть много разных способов сделать это!
Замечу, что автор JOpt Simple ведет очень похожий список! Нам нужен текст, чтобы превратить эти списки в таблицу с перечислением функций и достопримечательностей, чтобы мы, бедные пользователи, могли сделать осознанный выбор.
Не стесняйтесь добавлять github.com/Softhouse/jargo в этот список. Сейчас он довольно стабилен. Будем очень признательны за ранние отзывы этого сообщества.
Я создал Роп - github.com/ryenus/rop, в котором есть решение на основе аннотаций, в котором вы объявляете команды и параметры через простые классы и поля, что в значительной степени является декларативным способом создания синтаксических анализаторов командной строки. он может создавать приложения, подобные Git (single-cmd) или Maven (multi-cmd).
Ваш лучший: jewel-cli, я постоянно им пользуюсь.
Большинство перечисленных проектов по сути являются заброшенными. Пройдя по списку, я бы сказал, что наиболее популярными и активно поддерживаемыми пользователями являются commons-cli, jcommander, args4j, jopt-simple и picocli. Приношу свои извинения авторам таких вещей, как argparse4j и cli-parser - мне пришлось составить несколько произвольный рейтинг и выбрать пятерку лучших, очевидно, что другие проекты в списке популярны и все еще находятся в активной разработке.
... а вот и видео грузовика с 72 колесами -__________________________________-
Я прошу кого-нибудь указать дату последнего стабильного выпуска каждого парсера.
Ваша библиотека jewel-cli очень хороша. Он очень уникален по сравнению с другими библиотеками, с которыми я сталкивался, потому что использование интерфейсов устраняет много раздувания и допускает хорошее множественное наследование.
Я написал еще один: http://argparse4j.sourceforge.net/
Argparse4j - это библиотека парсера аргументов командной строки для Java, основанная на Python argparse.
Добро пожаловать в Stack Overflow! Спасибо, что разместили свой ответ! Обязательно внимательно прочтите FAQ по саморекламе.
авиакомпания @ Github выглядит хорошо. Он основан на аннотации и пытается имитировать структуры командной строки Git.
Это библиотека синтаксического анализа командной строки Google с открытым исходным кодом в рамках проекта Bazel. Лично я считаю, что это лучший вариант и намного проще, чем 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. И я не понимаю, как вы определяете варианты коротких / длинных / описаний ... Ура
It is 2021, time to do better than Commons CLI... :-)
Следует ли вам создать собственный синтаксический анализатор командной строки Java или использовать библиотеку?
Многие небольшие приложения, подобные служебным программам, вероятно, используют собственный синтаксический анализ командной строки, чтобы избежать дополнительной внешней зависимости. пикокли может быть интересной альтернативой.
Picocli - это современная библиотека и фреймворк для легкого создания мощных, удобных приложений командной строки с поддержкой GraalVM. Он находится в 1 исходном файле, поэтому приложения могут включать его в качестве источника, чтобы избежать добавления зависимости.
Он поддерживает цвета, автозаполнение, подкоманды и многое другое. Написано на Java, может использоваться из Groovy, Kotlin, Scala и т. д.
Функции:
<command> -xvfInputFile, а также <command> -x -v -f InputFile)"1..*", "3..5"Справочное сообщение по использованию легко изменить с помощью аннотаций (без программирования). Например:
(источник)
Я не удержался и добавил еще один снимок экрана, чтобы показать, какие справочные сообщения возможны. Помощь в использовании - это лицо вашего приложения, так что будьте изобретательны и получайте удовольствие!
Отказ от ответственности: я создал picocli. Отзывы или вопросы очень приветствуются.
Чистый гений! Жаль, что этот ответ похоронен на дне. Интерфейс командной строки Apache Commons многословен, содержит ошибки и долгое время не обновлялся. И я не хочу использовать парсер Google CLI, потому что мне не нужна таргетированная реклама на основе моей истории использования аргументов командной строки. Но в любом случае это выглядит немного более многословно, чем пикокли.
Я второй @Pete здесь ... Я просмотрел список выше, который был пустой тратой времени, так как это закопано внизу. Это должен быть лучший ответ на милю. Прекрасная работа! Мои требования не могли быть покрыты apache CLI или большинством других парсеров. Они были сложными даже для picocli, но они смогли дать мне наиболее близкий к синтаксису / поведению, который я хотел, и был достаточно гибким, чтобы взломать то, что мне действительно нужно. В качестве бонуса он отлично выглядит благодаря материалу ANSI.
@ShaiAlmog Самый популярный ответ - 10 лет назад и устарел. Я согласен с тем, что рекомендация Commons CLI в 2019 году вводит в заблуждение ИМХО. Пожалуйста, считайте переписывание лучшим ответом, чтобы сделать его более актуальным.
Я вижу, вы уже пробовали это, я не думаю, что это сработает и для меня ... Если бы вы выбрали имя типа 1Picoli, мы могли бы отсортировать третий ответ по алфавиту ;-)
Я думаю, что причина, по которой мое изменение было отменено, заключается в том, что я не раскрыл свою принадлежность (что я являюсь автором). У других людей не должно быть этой проблемы.
@RemkoPopma Я добавил pico к принятому ответу. Надеюсь, он прижится.
Это правильный ответ ! вы не ошибетесь с этой библиотекой
Если вам нужно что-то легкое (размер jar ~ 20 кб) и простое в использовании, вы можете попробовать анализатор аргументов. Он может использоваться в большинстве случаев использования, поддерживает указание массивов в аргументе и не зависит от какой-либо другой библиотеки. Он работает для 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);
}
Больше примеров можно найти здесь
Ссылка мертва. Вы убили свой проект? :-(
Argparse4j - лучшее, что я нашел. Он имитирует библиотеку Python argparse, которая очень удобна и мощна.
Я знаю, что большинство людей здесь найдут 10 миллионов причин, почему им не нравится мой путь, но это не важно. Я предпочитаю, чтобы все было просто, поэтому я просто отделяю ключ от значения с помощью '=' и сохраняю их в HashMap следующим образом:
Map<String, String> argsMap = new HashMap<>();
for (String arg: args) {
String[] parts = arg.split(" = ");
argsMap.put(parts[0], parts[1]);
}
Вы всегда можете вести список с ожидаемыми аргументами, чтобы помочь пользователю в случае, если он забыл аргумент или использовал неправильный ... Однако, если вам нужно слишком много функций, это решение в любом случае не для вас.
Как один из комментариев, упомянутых ранее (https://github.com/pcj/google-options), было бы хорошим выбором для начала.
Одна вещь, которую я хочу добавить:
1) Если вы столкнулись с какой-либо ошибкой отражения парсера, попробуйте использовать более новую версию файла guava. в моем случае:
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
Для пользователей Spring мы должны упомянуть также https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/SimpleCommandLinePropertySource.html и его брата-близнеца https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/JOptCommandLinePropertySource.html (реализация той же функциональности JOpt). Преимущество Spring заключается в том, что вы можете напрямую привязать аргументы командной строки к атрибутам, здесь есть пример https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/core/env/CommandLinePropertySource.html
Если вы уже используете 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);
}
}
И, наконец, если вам нужен доступ к вашим аргументам в bean-компоненте, просто введите ApplicationArguments:
@Component
public class MyBean {
@Autowired
private ApplicationArguments arguments;
// ...
}
Это круто :).
Я хочу показать вам свою реализацию: ReadyCLI
Преимущества:
Я разработал этот проект, поскольку мне требовались новые функции (параметры, флаг, подкоманды), которые можно было бы использовать в моих проектах самым простым способом.
См. Args4j и подробный пример его использования: martin-thoma.com/how-to-parse-command-line-arguments-in-java