I had tested the following methods to execute Linux command from my program
Method 1 : Assign all into a string
String temp1 = "'/"+t2+"/,/"+t1+"/p'";
String command2 = "sed -n "+temp1+" app.log";
Process p1 = Runtime.getRuntime().exec(command2);
Method 2 : use array
String [] command2 = new String []{"sed","-n","'/",t2,"/,/",t1,"/p'", "app.log";
System.out.println("The command2 is : "+Arrays.toString(command2);
Process p2 = new ProcessBuilder(command2).start();
This my reference link for the method 2 but both of the methods not working at all. This is the command I hope to run in the terminal sed -n '/14:32:54/,/14:33:44/p' app.log
This is a portion of my code for calling the system command, nothing displayed in line2 variable
String [] command2 = new String []{"sed","-n","'/",t2,"/,/",t1,"/p'","stlog.txt"};
Process p2 = new ProcessBuilder(command2).start();
BufferedReader br2 = new BufferedReader(new InputStreamReader(p2.getInputStream()));
String line2;
while((line2 = br2.readLine()) != null)
{
System.out.println(line2);
}
In my case worked:
ProcessBuilder processBuilder = new ProcessBuilder("/bin/bash", "-c", "pwd")
.directory(new File("some.directory.path"));
Process process = processBuilder.start();
Or you can sip using ProcessBuilder and just call
String command = "ping www.google.com";
String[] commandArray = {"/bin/bash", "-c", "pwd"};
Runtime.getRuntime().exec(commandArray);
"/bin/bash" 0 means that you are going to exec command in bach
"-c" -defines that next param is command
command - any command like "ping www.google.com" or "./script.sh" that you execute with terminal
you should just place your command instead of "ping www.google.com", but as you haven't specified directory - script will be executed from project directory (you can check it by executing "pwd" command that prints current directory). That is why ProcessBuilder is more preferable, as you can indicate execution directory there (replace "some.directory.path" with your dir).
.directory(new File("path/to/some/dir"));
Related
I have a function to execute a system command:
public String cmd(String s) {
String out = "";
try {
Runtime run = Runtime.getRuntime();
Process pr = run.exec(s.split(" "));
pr.waitFor();
BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line = "";
while ((line=buf.readLine())!=null) {
out+=line+"\n";
}
} catch(Exception e) {
e.printStackTrace();
}
return out;
}
The command passes through:
cmd("nmap -sL -n 192.168.1.0/24 | awk '/Nmap scan report/{print $NF}'");
Expected Output:
192.168.1.0
192.168.1.1
...
Actual Output:
Starting Nmap 7.80 ( https://nmap.org ) at 2021-04-12 20:27 EET
Nmap scan report for 192.168.1.0 ...
Similar questions answers this well:
Using Java ProcessBuilder to Execute a Piped Command
Java program not getting output from terminal
To execute a pipeline, you have to invoke a shell, and then run your commands inside that shell.
Process p = new ProcessBuilder().command("bash", "-c", command).start();
bash invokes a shell to execute your command and -c means commands are read from string. So, you don't have to send the command as an array in ProcessBuilder.
Adapted to you case
String cmd(String command) {
ProcessBuilder builder = new ProcessBuilder();
builder.redirectErrorStream(true); // add stdErr to output
Process process = builder.command("bash", "-c", command).start();
StringBuilder processOutput = new StringBuilder(); // add lines easier
// try-with to auto-close resources
try (BufferedReader processOutputReader = new BufferedReader(new InputStreamReader(process.getInputStream()));) {
String readLine;
while ((readLine = processOutputReader.readLine()) != null) {
processOutput.append(readLine + System.lineSeparator()); // use system's line-break
}
process.waitFor();
}
return processOutput.toString().trim();
}
Then call as expected:
cmd("nmap -sL -n 192.168.1.0/24 | awk '/Nmap scan report/{print $NF}'");
Note: I enhanced it a bit to
use try-with-resources to deal cleanly with resources
add output from StdErr
use a StringBuilder to concatenate output lines
use System.lineSeparator for platform-independency (Win/Mac/Linux/Unix)
Inspired by:
read the output from java exec
The pipe is interpreted by the shell. It executes one command then passes the output of one command into the next one. You could emulate this in Java starting both commands and then pumping the OutputStream of the first program to the InputStream of the second.
Alternatively if you don't want to do this you can still call something like "sh -c 'command1 | command2"
So i try to Execute an external program and capture the output.
Currently the part that execute command works fine (using .bat file) and i can see the output on the cmd window.
The part that need to read the output not and it seemt that it stack inside my while
This is what i have try:
String[] command = {"cmd.exe", "/C", "Start", "d:\\batFile.bat"};
Process process = Runtime.getRuntime().exec(command);
InputStream is = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
Update
This is my .bat file:
docker volume create --name=mydb
timeout 3
docker run -d -p 27017:27017 -v mydb:/data/db mongo
timeout 3
Maybe you can try to redirect the output like this :
Process runtimeProcess1;
ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/C","Start","d:\\batFile.bat");
pb.redirectOutput(Redirect.INHERIT);
pb.redirectError(Redirect.INHERIT);
pb.redirectInput(Redirect.INHERIT);
runtimeProcess1 = pb.start();
int processComplete1 = runtimeProcess1.waitFor();
With this, we can execute "build in" commands in java. However if we want to run some custom commands from this, Changing "pwd" to "device_id -l" doesn't work. "device_id -l" should list all the ids of attached devices of currently host. if "device_id -l" is executed in terminal itself. it works fine. There is not a question for the "build in" bash commands. Thank you.
String cmd = "pwd";
Runtime run = Runtime.getRuntime();
Process pr = run.exec(cmd);
pr.waitFor();
BufferedReader buf = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String line = "";
while ((line=buf.readLine())!=null)
System.out.println(line);
We can excuate
You can try using ProcessBuilder.
// create process
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "device_id", "-l");
// start process
Process p = pb.start();
// wait for process exit
p.waitFor();
// read process output
BufferedReader buf = new BufferedReader(newInputStreamReader(p.getInputStream()));
String line = "";
while ((line=buf.readLine())!=null)
System.out.println(line);
You need to split your command+arguments to a String array. In your case, if you want to execute "device_id -l", split that into an array like this:
String[] cmd = new String[] {"/full/path/to/device_id", "-l"};
Process pr = Runtime.getRuntime().exec(cmd);
And, you might want to use ProcessBuilder.
String[] cmd = new String[] {"/full/path/to/device_id", "-l"};
ProcessBuilder pb = new ProcessBuilder(cmd);
Process pr = pb.start();
Finally, you'll have to take into account that Java does not look for executables in PATH (like command shell does), you'll have to provide full path to the executable/script that you want to execute (or it has to be in the working directory; you can set the working directory with ProcessBuilder.directory(File)).
See also: Difference between ProcessBuilder and Runtime.exec()
I am trying to execute originate command in specific directory "/usr/local/freeswitch/bin", In bin I have to run executable file fs_cli by ./fs_cli command, In fs_cli I have to execute following command
originate loopback/1234/default &bridge(sofia/internal/1789)
Its working fine from terminal, The same command can be executed from bin
./fs_cli -x "originate loopback/1234/default &bridge(sofia/internal/1789)"
I tried folowing java program to do the above task
Process pr = Runtime.getRuntime().exec("./fs_cli -x \"originate loopback/1234/default &bridge(sofia/internal/1789#192.168.0.198)\"");
BufferedReader br = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String str = null;
while ((str = br.readLine()) != null) {
System.out.println(str);
}
I have creted symbolic link of fs_cli and placed in current location
The above program is showing following output
Output
-ERR "originate Command not found!
As far as I am concerned whwn above command is working fine with terminal it should be the same from java, So it shows I am wrong somewhere
Please help me to sort out this problem.
Use ProcessBuilder and supply a directory path
ProcessBuilder pb = new ProcessBuilder(
"./fs_cli",
"-x",
"originate loopback/1234/default &bridge(sofia/internal/1789#192.168.0.198)");
pb.directory(new File("..."));
Process pr = pb.start();
BufferedReader br = new BufferedReader(new InputStreamReader(pr.getInputStream()));
String str = null;
while ((str = br.readLine()) != null) {
System.out.println(str);
}
Where possible, you should provide the command arguments as separate Strings, this will pass each as a separate argument to the process and take care of those arguments that need to be escaped by quotes for you (unless it's expecting the quotes, then you should include them anyway)
The other way is:
ProcessBuilder processBuilder = new ProcessBuilder( "/bin/bash", "-c", "cd /usr/local/freeswitch/bin && ./fs_cli -x \"originate loopback/1234/default &bridge(sofia/internal/1789)\"" );
processBuilder.start();
I am trying to execute a shell script with command line arguments using ProcessBuilder, this shell script inturn calls two other shell scripts that uses this argument. The first shell script runs fine, but when the second one is started it returns exit code 1.
ProcessBuilder snippet from Java Program:
//scenario - A string that holds a numerical value like 1 or 2 etc
String[] command2 = {"/bin/bash", "<path to shell script>/runTemporaryTestSuite.sh", scenario};
ProcessBuilder pb2 = new ProcessBuilder(command2);
Process p2 = pb2.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p2.getInputStream()));
String line;
//print - is an object ref of response.getWriter() //
print.println("Output of running "+Arrays.toString(command2)+" is: ");
while ((line = br.readLine()) != null) {
print.println(line);
}
try {
int exitValue = p2.waitFor();
print.println("<br><br>Exit Value of p2 is " + exitValue);
} catch (InterruptedException e) {
e.printStackTrace();
}
runTemporaryTestSuite.sh
#!/bin/bash
sh <path to script>/clearRegressionResult.sh (This runs fine)
sh <path to script>/startRegression.sh $1 (This is where the issue occurs)
startRegression.sh looks like:
SUITE_PATH="./"
java -DconfigPath=${SUITE_PATH}/config.xml -Dscenario=$1 -Dauto=true -jar test.jar
My output:
Output of running [/bin/bash, /runTemporaryTestSuite.sh, 29] is:
Exit Value of p2 is 1
Any help in resolving this is really appreciated.
In think the problem is not that you cannot launch shell script with arguments, I was curious and I did a test
public class Main {
public static void main(String[] args) throws IOException {
String[] command = {"/bin/bash", "test.sh", "Argument1"};
ProcessBuilder p = new ProcessBuilder(command);
Process p2 = p.start();
BufferedReader br = new BufferedReader(new InputStreamReader(p2.getInputStream()));
String line;
System.out.println("Output of running " + command + " is: ");
while ((line = br.readLine()) != null) {
System.out.println(line);
}
}
here is the test.sh script
echo Hello im the script, here your args $#
Here the output
Output of running [Ljava.lang.String;#604e9f7f is:
Hello im the script, here your args Argument1
What I think is just that your startRegression.sh exit with a non-0 status (aka it failed somewhere) and it have repercussion, runTemporaryTestSuite.sh will also exit with a non-zero status, and so on hence the message : Exit Value of p2 is 1
What I see right now,
SUITE_PATH="./"
java -DconfigPath=${SUITE_PATH}/config.xml [..] the configPath will be .//config.xml so maybe you have a plain file not found issue? I might be wrong, hope it helped