How to run long command in ProcessBuilder - java

I am trying to use this command:
git checkout `git rev-list -n 1 --before="2009-07-27 13:37" master`
Which I am running through ProcessBuilder. Now, I know that the rest of my code works, as I have tested it with other examples. But I am not sure how to split this command so that it works for ProcessBuilder.
Apparently, this method did not work:
String[] command = {"git", "checkout", "`git rev-list -n 1 --before=\"2014-01-01 12:00\" master`"};
This did not work as well:
String[] command = {"git", "checkout", "`git", "rev-list", "-n", "1", "--before=\"2014-01-01 12:00\"", "master`"};
I am also not getting any output from the console (I do InputStream), which means it's harder for me to figure out what's the issue. I am thinking the problem should be obvious to people familiar enough with ProcessBuilders, so yeah...
The rest of my code looks as such:
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.directory(new File(fullPath));
process = processBuilder.start();
And the path for the directory should be correct as I checked it (it is inside of the main directory of the repository).
If by any chance I need to provide other parts of the code, I will.

The back-ticks are actually handled by the unix shell - Java doesn't process them. When using process builder you should execute the command given in the back-ticks and pass the output as parameters to the second command. A simple example is below: (using 'ls').
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
public class ProcessBuilderTest {
public static void main(String[] args) throws IOException, InterruptedException {
// Command: ls `ls /etc/passwd /etc/services`
// Read the output from the command second ls...
ProcessBuilder pb = new ProcessBuilder("ls", "/etc/passwd", "/etc/services");
Process process = pb.start();
InputStream is = process.getInputStream();
List<String> lines = IOUtils.readLines(is, Charset.defaultCharset());
ArrayList<String> cmdParts = new ArrayList<>();
cmdParts.add("ls");
cmdParts.addAll(lines);
// Construct the second command
ProcessBuilder pbLs = new ProcessBuilder(cmdParts);
Process lsProcess = pbLs.start();
System.out.println(IOUtils.readLines(lsProcess.getInputStream(), Charset.defaultCharset()));
lsProcess.waitFor();
}
}

Related

Running command in linux environment fails

I am trying to execute a command via Runtime.getRuntime().exec().
When i run the following command in my linux bash it works fine.
Command: bash -c "npm -v"
But when i try to run it with Java it fails with the following error:
-v": -c: line 0: unexpected EOF while looking for matching `"'
-v": -c: line 1: syntax error: unexpected end of file
Reproducible example:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
public class RunACommandTest
{
public static void main(String[] args)
{
try
{
Process exec = Runtime.getRuntime().exec("bash -c \"npm -v\"");
new BufferedReader(new InputStreamReader(exec.getInputStream(), StandardCharsets.UTF_8))
.lines()
.forEachOrdered(line -> System.out.println("IN " + line));
new BufferedReader(new InputStreamReader(exec.getErrorStream(), StandardCharsets.UTF_8))
.lines()
.forEachOrdered(line -> System.out.println("ERR " + line));
}
catch(IOException e)
{
throw new RuntimeException(e);
}
}
}
I have also tried to use single quotes instead of double quotes.
Unfortunately the now deprecated Runtime.exec(String) breaks up this command incorrectly as 4 argument command { "bash", "-c", "\"npm", "-v\"" }. Separating the parameter list as 3 argument command { "bash", "-c", "npm -v" } will avoid this problem.
It is easier to use ProcessBuilder which is used internally by Runtime.exec:
ProcessBuilder pb = new ProcessBuilder("bash","-c", "npm -v");
Process exec = pb.start();
Note that you must consume stdout + stderr in separate threads. What you have above may work, but it may freeze for other processes or conditions. You can avoid by redirect to file, or redirect error to stdout with:
pb.redirectErrorStream(true);

Cannot run python script from java jar

While working in IntelliJ everything worked but after I built jar it stopped. At first, it was just me forgetting to put it in jar build config, but now after making sure it is there, I still can't run it. These are ways I try:
InputStream script = mainView.class.getResourceAsStream("vizualize3D.py");
Process process = new ProcessBuilder("python3", "-").start() ;
Process p1 = Runtime.getRuntime().exec("python3 " + script);
Runtime rt = Runtime.getRuntime();
Process pr = rt.exec("python3 " + mainView.class.getResourceAsStream("vizualize3D.py"));
None of theme work despite having it in resources. I also tried to specify path to it in IntelliJ project and it works but only when run from IntelliJ after I start it from jar it doesn't.
Edit1:
For people that didn't understand py file is in jar file
None of the options involving you trying to execute "python3 "+script, and equivalents, will work. script is an InputStream, not a path on the file system, so simply concatenating it with a String will not give you anything meaningful. Additionally, since your script is not in its own file, and there's no simple way for the python interpreter to extract it, simply invoking it like this won't work.
What you can do, however, is to execute
python3 -
The - option here (at least on BSD-like systems) means "read from standard input, and interpret it as a script". Then, on the Java side, you can read the jar-packaged resource as a stream and pipe it to the python process's standard input.
For details on choosing the correct path for the resource, see How do I determine the correct path for FXML files, CSS files, Images, and other resources needed by my JavaFX Application?.
The following, in which the script is simply placed in the same package as the class, works for me:
PythonRunner.java:
package example.python;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
public class PythonRunner {
public static void main(String[] args) throws Exception {
String pythonInterpreter = "/usr/bin/python3" ; // default
if (args.length > 0) {
pythonInterpreter = args[0] ;
}
InputStream script = PythonRunner.class.getResourceAsStream("script.py");
Process pythonProcess = new ProcessBuilder(pythonInterpreter, "-")
.start();
// This thread reads the output from the process and
// processes it (in this case just dumps it to standard out)
new Thread(() -> {
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(pythonProcess.getInputStream()))) {
for (String line ; (line = reader.readLine()) != null ;) {
System.out.println(line);
}
} catch (IOException exc) {
exc.printStackTrace();
}
}).start();
// read the script from the resource, and pipe it to the
// python process's standard input (which will be read because
// of the '-' option)
OutputStream stdin = pythonProcess.getOutputStream();
byte[] buffer = new byte[1024];
for (int read = 0 ; read >= 0 ; read = script.read(buffer)) {
stdin.write(buffer, 0, read);
}
stdin.close();
}
}
script.py:
import sys
for i in range(10):
print("Spam")
sys.exit(0)
MANIFEST.MF
Manifest-Version: 1.0
Main-Class: example.python.PythonRunner
Eclipse layout:
Jar contents and result of running:
$ jar tf runPython.jar
META-INF/MANIFEST.MF
example/python/PythonRunner.class
example/python/script.py
$ java -jar runPython.jar
Spam
Spam
Spam
Spam
Spam
Spam
Spam
Spam
Spam
Spam
$

How do I print the list of files and folders in a root directory in linux using java

I am new to both Java and Linux, I was trying to use some Runtime.exec() commands that would allow my program to execute commands in Linux such as "cd /mnt/" and "ls --group-directories-first" to list files and directories contained in /mnt/ but I think I am making a problem with the execution.
I tried my code to only include the "ls --group-directories-first" and it worked like a charm, only problem was, it only listed subdirectories and files in the projects folder. I wanted to make my program go to /mnt/ first so I made my command line to a command array by using exec(String[] cmdarray) format as process1 = Runtime.getRuntime().exec(new String[]{"cd /mnt/","ls --group-directories-first"}); and when I ran it on linux, it just got executed without any printed runtime errors but also without any feedback/printed lines.
Here is my code:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class linCom {
public static void main(String args[]) {
String s;
Process p;
try {
p = Runtime.getRuntime().exec("ls --group-directories-first");
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
p.destroy();
} catch (Exception e) {}
}
}
This worked and printed out:
"line: DummyFolder1
line: linCom.class
line: linCom.java
exit: 0"
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class linCom {
public static void main(String args[]) {
String s;
Process p;
try {
p = Runtime.getRuntime().exec(new String[]{"cd /mnt/","ls --group-directories-first"});
BufferedReader br = new BufferedReader(
new InputStreamReader(p.getInputStream()));
while ((s = br.readLine()) != null)
System.out.println("line: " + s);
p.waitFor();
System.out.println ("exit: " + p.exitValue());
p.destroy();
} catch (Exception e) {}
}
}
This just got executed with no printed lines.
I expected my program to just go to the /mnt/ directory and print out subdirectories and files on there, but it just got executed with no visible runtime errors and no printed lines.
I have looked at other entries but could not find any answer to my problem.
EDIT: I changed "no errors" with "no error messages" to make it clear that if program had any errors, I did not get any feedback about it.
Here's where the UNIX process model can be confusing.
What you have tries to run the program named cd /mnt/ with the first parameter of ls --group-directories-first . Unix programs can be named anything (they're just filenames) but there's no program named cd /mnt. And anyway, the cd operation is actually performed by a shell, not as a forked/execed program.
You hope to run this shell command from your Java program: cd /mnt/; ls --group-directories-first . The trouble is, Java's .exec() method does not give you a shell, so shell commands don't work.
You can try this instead. It's like running the shell command
/bin/sh -c "cd /mnt/; ls --group-directories-first"
With this, you start a shell, then tell it to run -cthe command you want.
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh",
"-c",
"cd /mnt/; ls --group-directories-first"});
But it's quite dependent on the machine where your Java program runs, so be careful.
Reference: How to invoke a Linux shell command from Java
Do not use an external process just to list files. Java has plenty of ways to do that. All of them are in the Files class. For example:
Path dir = Paths.get("/mnt");
try (Stream<Path> files = Files.list(dir).sorted(
Comparator.comparing((Path p) -> !Files.isDirectory(p))
.thenComparing(Comparator.naturalOrder()))) {
files.forEach(System.out::println);
}
Do you really need to use Runtime.exec()comands? That would make your code platafform dependent.
You could use File.listFiles():
File folder = new File("/mnt");
for (File f : folder.listFiles()) {
System.out.println(f.getName());
}
That would make the code less plataform dependent

Java - ProcessBuilder is not outputting my python file

Some context: I'm trying to make a GUI on java and have python code run once I click a button on the GUI. For example if I press start on the java GUI, it will run the python code on file .py.
Why is it not outputting anything? You can also try this by creating a test python file and just inputting your own file location into the code below.
Code so far:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import javax.swing.JFrame;
public class main_gui extends JFrame {
public static void main(String[] args) throws Exception {
ProcessBuilder builder = new ProcessBuilder("cmd.exe",
"cd \"G:\\...Javaa\\filetranslatorapplication\\file_translator_app.py");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while (true) {
line = r.readLine();
if (line == null) {
break;
}
System.out.println(line);
}
}
}
Two things to keep in mind:
The python file in NOT in the same place as this java file.
The java file and python file are both on a usb, hence the "G:\..".
Also, if anyone has a better way of running python code through java gui, please feel free to point me in the right direction.
The following should work for you:
ProcessBuilder builder = new ProcessBuilder("cmd",
"/c \"G: && python Javaa\\filetranslatorapplication\\file_translator_app.py\"");
This gets executed when I run my Java application from a different drive. But, for you, if it is the same drive, need not switch to G:. You may execute the py file with python command.
Your process simply does not make sense.
It simply spawn a cmd, and cd to an invalid directory (as it is a file).
What you want is probably
cmd /c python g:\your\path\foo.py
or
cmd /c g:\your\path\foo.py
or simply
may\be\full\path\is\needed\python g:\your\path\foo.py
So, your code should look like:
ProcessBuilder builder
= new ProcessBuilder("cmd.exe", "/c", "python", "g:\\yourpath\\file_translator_app.py");
// or
// = new ProcessBuilder("python", "g:\\yourpath\\file_translator_app.py");
// or
// = new ProcessBuilder("cmd", "/c", "g:\\yourpath\\file_translator_app.py");

How to run sed command from java code

I'm probably missing something, but I'm trying to run commandline from a java
The code is as following:
String command = "sed -i 's/\\^#\\^/\\|/g' /tmp/part-00000-00000";
ProcessBuilder pb = new ProcessBuilder(command);
pb.redirectErrorStream(true);
Process process = pb.start();
process.waitFor();
if (process.exitValue() > 0) {
String output = // get output form command
throw new Exception(output);
}
I'm getting the following error:
java.lang.Exception: Cannot run program "sed -i 's/\^#\^/\|/g' /tmp/part-00000-00000": error=2, No such file or directory
The fils is exists. I'm doing ll on this file and it is exists.
I'm just looking for a way to make it work from java. What am I doing wrong?
Pass the command as an array, not a string:
String[] command={"sed", "-i", "'s/\\^#\\^/\\|/g'", "/tmp/part-00000-00000"};
See ProcessBuilder documentation.
Honestly there is no need to externally execute sed in this case. Read the file in Java and use Pattern. Then you have code that could run on any platform. Combine this with org.apache.commons.io.FileUtils and you can do it in a few lines of code.
Alternatively, you could use java.util.Scanner to avoid loading the whole file into memory.
final File = new File("/tmp/part-00000-00000");
String contents = FileUtils.readFileToString(file, StandardCharsets.UTF_8.name());
contents = Pattern.compile("\\^#\\^/\\").matcher(contents).replaceAll("|");
FileUtils.write(file, contents);
Or, in a short, self-contained, correct example
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;
public final class SedUtil {
public static void main(String... args) throws Exception {
final File file = new File("part-00000-00000");
final String data = "trombone ^#^ shorty";
FileUtils.write(file, data);
sed(file, Pattern.compile("\\^#\\^"), "|");
System.out.println(data);
System.out.println(FileUtils.readFileToString(file, StandardCharsets.UTF_8));
}
public static void sed(File file, Pattern regex, String value) throws IOException {
String contents = FileUtils.readFileToString(file, StandardCharsets.UTF_8.name());
contents = regex.matcher(contents).replaceAll(value);
FileUtils.write(file, contents);
}
}
which gives output
trombone ^#^ shorty
trombone | shorty
this code here is magic really, simple and short and tested 100%
example i want to remove the last character of line from file (/sdcard/MT2/file.json)
String[] cmdline = { "sh", "-c", "sed -i 's/.$//' /sdcard/MT2/file.json " };
try {
Runtime.getRuntime().exec(cmdline);
} catch (Exception s) {
finishAffinity();
}
this magic code here don't run only sed, but also runnig echo, cat, ....ect
good luck
Try
Process p = Runtime.getRuntime().exec("sed -i 's/\\^#\\^/\\|/g' /tmp/part-00000-00000");

Categories