Выполнение однострочного кода Bash с разными кавычками из кода Java для запроса Elasticsearch

Я пытаюсь выполнить почтовый запрос 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. Я предполагаю, что это как-то связано с форматированием и использованием одинарных кавычек, но я еще не смог запустить его непосредственно из своего кода.

Настоятельно рекомендуется использовать HTTP-клиент Apache или другую HTTP-библиотеку Java вместо запуска CURL поверх IPC. Вы делаете свою Java-программу менее переносимой, выполняя трехмерные сторонние процессы из кода. По крайней мере, вам нужно будет изменить свой код для UNIX (Linux, FreeBSD, MacOS X) и Windows при запуске CURL.

Victor Gubin 13.05.2019 10:48

Я отредактировал ваш заголовок, чтобы люди с похожими проблемами могли лучше найти ваш вопрос.

Michael Jaros 13.05.2019 11:02
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
2
2
463
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Разделение аргументов и правильное цитирование может быть сложным, если использовать только 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();

Также неплохо подождать, если дочерний процесс заканчивается. А затем проверьте код выхода

Victor Gubin 13.05.2019 10:42

@CobraKai Рад, что смог помочь. Поскольку ваша проблема была решена, отметьте ответ как принятый. Это заставит сообщение отображаться как отвеченное и может помочь другим людям с похожей проблемой.

pitprok 13.05.2019 16:56

Лучший подход

Пожалуйста, ознакомьтесь с другими ответами для предложений о лучшем подходе.

Как исправить этот подход

Это правильное (и сложное) цитирование для вашего текущего подхода:

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.

Вот почему мы должны закончить одинарную кавычку, начать двойную кавычку (где одинарную кавычку можно экранировать), закончить двойную кавычку и снова продолжить нашу одинарную кавычку.

Спасибо чувак. Использовал один из предыдущих предложенных методов, чтобы исправить это.

CobraKai 13.05.2019 10:54

Другие вопросы по теме