Я пытаюсь выполнить почтовый запрос Elastic search в моем Java-коде. я хочу, чтобы код выполнялся на моей машине с помощью оболочки bash.
Вот мой код:
public class Elastic {
public static void main(String[] args) {
String cmd = "curl -X PUT IP:PORT/twitter/_doc/10 -H 'Content-Type: application/json' -d '{ \"user\" : \"Bob\", \"post_date\" : \"2019-12-15T14:12:10\", \"message\" : \"trying out Elasticsearch\" }' ";
try {
Process pr = Runtime.getRuntime().exec(cmd);
} catch (Exception e) {
e.printStackTrace();
}
/*
try {
Runtime.getRuntime().exec("/bin/bash "+"-c "+"\'"+cmd+"\'");
} catch (Exception e) {
e.printStackTrace();
} */
System.out.println("============== = ");
System.out.println(cmd);
}
}
Я пытался сделать это двумя разными способами, как вы можете видеть из кода, который был закомментирован.
Я печатаю запрос, который я построил, чтобы проверить его. Когда я запускаю эту программу на своем локальном компьютере и пытаюсь распечатать запрос в терминале, он работает, но не в моем коде Java/запросе bash. Я предполагаю, что это как-то связано с форматированием и использованием одинарных кавычек, но я еще не смог запустить его непосредственно из своего кода.
Я отредактировал ваш заголовок, чтобы люди с похожими проблемами могли лучше найти ваш вопрос.




Разделение аргументов и правильное цитирование может быть сложным, если использовать только Runtime.exec.
Я бы порекомендовал вам взглянуть на более надежный API процесса построителя, если вам нужно передавать сложные аргументы, такие как json.
Вы можете попробовать написать скрипт в отдельном файле, а затем использовать
String[] cmdScript = new String[]{"/bin/bash", "path/to/myScript.sh"};
Process procScript = Runtime.getRuntime().exec(cmdScript);
Если вы также хотите добавить параметры, вы можете использовать что-то вроде
Process procBuildScript = new ProcessBuilder("path/to/myScript.sh", "myArg1 myArg2").start();
Также неплохо подождать, если дочерний процесс заканчивается. А затем проверьте код выхода
@CobraKai Рад, что смог помочь. Поскольку ваша проблема была решена, отметьте ответ как принятый. Это заставит сообщение отображаться как отвеченное и может помочь другим людям с похожей проблемой.
Лучший подход
Пожалуйста, ознакомьтесь с другими ответами для предложений о лучшем подходе.
Как исправить этот подход
Это правильное (и сложное) цитирование для вашего текущего подхода:
String cmd = "curl -X PUT IP:PORT/twitter/_doc/10 -H '"\'"'Content-Type: application/json'"\'"' -d '"\'"'{ \"user\" : \"Bob\", \"post_date\" : \"2019-12-15T14:12:10\", \"message\" : \"trying out Elasticsearch\" }'"\'"' ";
[...]
Runtime.getRuntime().exec("/bin/bash "+"-c "+"'"+cmd+"'");
Внутри строки, переданной оболочке в одинарных кавычках, вы экранируете другие одинарные кавычки, заканчивая текущую одинарную кавычку ('), начиная двойную кавычку ("), добавляя экранированную одинарную кавычку (\'), закрывая двойную кавычку (") и продолжение строки в одинарных кавычках (').
В совокупности мы пишем это как '"\'"', в контексте это bli '"\'"'single-quote-inside-json'"\'"' bla, которое становится /bin/bash -c 'bli '"\'"'single-quote-inside-json'"\'"' bla'.
Почему так сложно?
Причина, по которой это необходимо, можно найти на странице руководства bash(1):
A single quote may not occur between single quotes, even when preceded by a backslash.
Вот почему мы должны закончить одинарную кавычку, начать двойную кавычку (где одинарную кавычку можно экранировать), закончить двойную кавычку и снова продолжить нашу одинарную кавычку.
Спасибо чувак. Использовал один из предыдущих предложенных методов, чтобы исправить это.
Настоятельно рекомендуется использовать HTTP-клиент Apache или другую HTTP-библиотеку Java вместо запуска CURL поверх IPC. Вы делаете свою Java-программу менее переносимой, выполняя трехмерные сторонние процессы из кода. По крайней мере, вам нужно будет изменить свой код для UNIX (Linux, FreeBSD, MacOS X) и Windows при запуске CURL.