Run linux command through java. - java

I want to run nm command in linux through java.
I tried this code :
command = "nm -l file1.o > file1.txt";
Process p = Runtime.getRuntime().exec(command);
But it's not working, what is wrong with the code?

That is not an executable, it is in fact a shell script.
If you invoke the shell with -c, then you can execute your command:
/bin/sh -c "command > here"

Here's what you need to do:
String command = "nm -l file1.o > file1.txt";
Process p = Runtime.getRuntime().exec(new String[]{"/bin/sh", "-c", command});
The following "simple answer" WON'T WORK :
String command = "/bin/sh -c 'nm -l file1.o > file1.txt'";
Process p = Runtime.getRuntime().exec(command);
because the exec(String) method splits its the string naively using whitespace as the separator and ignoring any quoting. So the above example is equivalent to supplying the following command / argument list.
new String[]{"/bin/sh", "-c", "'nm", "-l", "file1.o", ">", "file1.txt'"};

An alternative to pipe would be to read the stdout of your command, see Java exec() does not return expected result of pipes' connected commands for an example.
Instead of redirecting the output using "> file.txt" you would read whatever the output is and write it to a StringBuffer or OutputStream or whatever you like.
This would have the advantage that you could also read stderr and see if there were errors (like no space left on device etc.). (you can also do that using "2>" using your approach)

Related

Pipe ("|") doesn't work with ProcessBuilder in Android [duplicate]

I'm trying to use Java's ProcessBuilder class to execute a command that has a pipe in it. For example:
ls -l | grep foo
However, I get an error:
ls: |: no such file or directory
Followed by:
ls: grep: no such file or directory
Even though that command works perfectly from the command line, I can not get ProcessBuilder to execute a command that redirects its output to another.
Is there any way to accomplish this?
This should work:
ProcessBuilder b = new ProcessBuilder("/bin/sh", "-c", "ls -l| grep foo");
To execute a pipeline, you have to invoke a shell, and then run your commands inside that shell.
The simplest way is to invoke the shell with the command line as the parameter. After all, it's the shell which is interpreting "|" to mean "pipe the data between two processes".
Alternatively, you could launch each process separately, and read from the standard output of "ls -l", writing the data to the standard input of "grep" in your example.
Since Java 9, there’s genuine support for piplines in ProcessBuilder.
So you can use
List<String> result;
List<Process> processes = ProcessBuilder.startPipeline(List.of(
new ProcessBuilder("ls", "-l")
.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE),
new ProcessBuilder("grep", "foo")
.redirectError(ProcessBuilder.Redirect.INHERIT)
));
try(Scanner s = new Scanner(processes.get(processes.size() - 1).getInputStream())) {
result = s.useDelimiter("\\R").tokens().toList();
}
to get the matching lines in a list.
Or, for Windows
List<String> result;
List<Process> processes = ProcessBuilder.startPipeline(List.of(
new ProcessBuilder("cmd", "/c", "dir")
.inheritIO().redirectOutput(ProcessBuilder.Redirect.PIPE),
new ProcessBuilder("find", "\"foo\"")
.redirectError(ProcessBuilder.Redirect.INHERIT)
));
try(Scanner s = new Scanner(processes.get(processes.size() - 1).getInputStream())) {
result = s.useDelimiter("\\R").tokens().toList();
}
These examples redirect stdin of the first process and all error streams to inherit, to use the same as the Java process.
You can also call .redirectOutput(ProcessBuilder.Redirect.INHERIT) on the ProcessBuilder of the last process, to print the results directly to the console (or wherever stdout has been redirected to).

Incomplete output about Java Runtime.getRuntime().exec(command)

I want to build an app like Jenkins terminal:
And I use Java Runtime.getRuntime().exec(command) to execute the command, find out that the output is incomplete.
textshell.sh:
# textshell.sh
echo "wwwwwww";
sleep 2
ls
For example:
When I execute textshell.sh in my mac terminalsh -x testshell.sh , output :
+ echo wwwwwww
wwwwwww
+ sleep 2
+ ls
testshell.sh
but when I execute by java Java Runtime.getRuntime().exec("sh -x testshell.sh") , output:
wwwwwww
testshell.sh
the shell args -x seems useless
How can I fix it?
As #Joachim Sauer points out you are not reading STDERR so miss the lines of echo output from the set -x output. Adjust your code to access the process.getErrorStream() as well.
Alternatively you can switch to ProcessBuilder if wanting to read the error stream merged with the output:
String[]cmd = new String[]{"sh", "-x", "testshell.sh"}
ProcessBuilder pb = new ProcessBuilder(cmd);
// THIS MERGES STDERR>STDOUT:
pb.redirectErrorStream(true);
// EITHER send all output to a file here:
Path stdout = Path.of("mergedio.txt");
pb.redirectOutput(stdout.toFile());
Process p = pb.start();
// OR consume your STDOUT p.getInputStream() here as before:
int rc = p.waitFor();
System.out.println("STDOUT: \""+Files.readString(stdout)+'"');

Execute bash in java

Wen i try to run this code :
String[] cmd = {"/bin/bash", "-c", "printf '%s'\n"+videoPath+"./"+"*.mp4 >"+"mylist.txt"};
processBuilder.command(cmd);
I get some error:
/bin/bash: line 1:
/home/gilles/eclipse-workspace/informationGewinnungApp/videotool/outputs/./info.mp4:
cannot execute binary file: Exec format error 126
The \n in your string is expanded into a newline. Hence bash sees two commands,
printf %s
..../info.mp4
Do it either as
String[] cmd = {"/bin/bash", "-c", "printf '%s' "+videoPath+"./"+"*.mp4 >"+"mylist.txt"};
Or
String[] cmd = {"/bin/bash", "-c", "echo "+videoPath+"./"+"*.mp4 >"+"mylist.txt"};
But: Why don't you want to use a bash child process, if you only want to create a new file containing a certain string? Wouldn't it be easier to do it directly from Java?

run python script inside Java

I need to run a shell command in Windows:
c:\Python27\python.exe c:\probabilistic_cracker\process.py dic2.txt
which is running fine in a command shell.
In Java I do this:
ProcessBuilder pb = new ProcessBuilder(Arrays.asList("c:\\Python27\\python", " c:\\probabilistic_cracker\\process.py"," dic2.txt"));
Process p = pb.start();
or this
ProcessBuilder pb = new ProcessBuilder("c:\\Python27\\python", " c:\\probabilistic_cracker\\process.py"," dic2.txt");
in both cases the result is
c:\Python27\python: can't open file ' c:\probabilistic_cracker\process.py': [Errno 22] Invalid argument
Your command is built correctly but the way you pass it to ProcessBuilder isn't, as stated in its documentation you pass the args directly the way they are, there's no need to add spaces since the ProcessBuilder will take care of that for you.
ProcessBuilder pb = new ProcessBuilder("c:\\Python27\\python", "c:\\probabilistic_cracker\\process.py","dic2.txt");
So just removing those whitespaces you have in the beginning of each argument string will do the trick.

Linux shell commands behave strange with Runtime.exec() (screen command)

I am sitting here since at least allways on a problem that really beats me down!
I'm writing on a simple and small java program that easily passes any command to a (linux) screen session.
Shell command: bash -c "screen -p 0 -S sessionname -X eval 'stuff \"some command\"\015'"
When I enter this in the command shell, it all works fine!
But if I let a Java programm do this, nothing happens at all! Not even a message or error or hint! Simply nothing!
I let the program echo the generated screen command and if I take that output and paste it into the shell, it works.
Here is my Java code:
static public void screenCmd() throws IOException
{
String command = "bash -c \"screen -p 0 -S screenname -X eval 'stuff \\\"cmd\\\"\\015'\"";
System.out.println("debug: '" + command + "'"); //output would work
//when copy and paste it to the shell
InputStreamReader isr = new InputStreamReader(
Runtime.getRuntime().exec(command).getInputStream()
);
//for debug output
BufferedReader br = new BufferedReader(isr);
String line = "";
while ((line = br.readLine()) != null)
System.out.println(line);
}
The funniest thing is, that all the other shell commands are working.
I tried Java to exec tail, whomi, cp, ls, ... without any problem. Why not screen?
The Java program is started by the same user who started the screen session.
If somebody has an even small idea please report! I am driving insane here!
p.s.: The screen session also runs a java program! (could that be part of the problem?)
Thanks.
I'd recommend that you try the more modern ProcessBuilder class.
And read these:
Five Common java.lang.Process Pitfalls
When Runtime.exec() won't
From Runtime.exec() to ProcessBuilder
The real problem is the way the command line is parsed: Java's Runtime.exec doesn't follow the same quoting rules as Bash. You should use the array version of the API instead:
String[] command = {"bash", "-c",
"screen -p 0 -S screenname -X eval 'stuff \\\"cmd\\\"\\015'"};
Runtime.getRuntime().exec(command);
You can reduce some of the quoting mess if you exec screen directly without going through bash:
String[] command = {"screen", "-p", "0",
"-S", "10624.pts-2.koivu", "-X", "eval", "stuff \"cmd\"\\015"};

Categories

Resources