Execute Bash one-liner with different quotes from Java code for Elasticsearch query Execute Bash one-liner with different quotes from Java code for Elasticsearch query elasticsearch elasticsearch

Execute Bash one-liner with different quotes from Java code for Elasticsearch query


You could try to write the script in a separate file and then use

String[] cmdScript = new String[]{"/bin/bash", "path/to/myScript.sh"}; Process procScript = Runtime.getRuntime().exec(cmdScript);

If you also want to add parameters you could use something like

Process procBuildScript = new ProcessBuilder("path/to/myScript.sh", "myArg1 myArg2").start();


Best approach

Please see the other answers for suggestions on an altogether better approach.

How to fix this approach

This is the correct (and tricky) quoting for your current approach:

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+"'");

Inside the string passed to the shell inside single quotes, you escape other single quotes by ending the current single quote ('), starting a double quote ("), adding an escaped single quote (\'), closing the double quote (") and continuing the single-quoted string (').

Put together, we write this as '"\'"', with context it is bli '"\'"'single-quote-inside-json'"\'"' bla, which becomes /bin/bash -c 'bli '"\'"'single-quote-inside-json'"\'"' bla'.

Why so complicated?

The reason why this is necessary can be found in the bash(1) manual page:

A single quote may not occur between single quotes, even when preceded by a backslash.

That's why we must end the single quote, start a double quote (where the single quote can be escaped), end the double quote, and continue our single quote again.


Separating arguments and quoting correctly can be tricky to get right using only Runtime.exec.

I'd recommend you have a look at the more robust ProcessBuilder API if you need to pass complex arguments like json.