Executing shell script which contains a while loop from Java - java

I am having a critical trouble to execute a shell script which contains a while loop. Here is my shell script:
echo Here 1
sleep 0.05
echo Here 2
sleep 0.05
echo Here 3
ic=70
while [ $ic -ge 40 ]
do
#sleep 0.05
ic=$[$ic-1]
echo Here $ic
done
When I am executing the script normally from the terminal as /home/pi/tbe/testSleep.sh it is working. and printing all the echos.
Now I have written this java method to execute the file:
public static void main(String[] args) throws IOException, InterruptedException {
String command = "/home/pi/tbe/testSleep.sh";
System.out.println("Executing command: " + command);
Process process = new ProcessBuilder(command).start();
BufferedReader reader = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
process.waitFor();
int exitValue = process.exitValue();
System.out.println("Command executed. Exit value: " + exitValue);
process.destroy();
}
And when I am executing it I can only see the following output:
Executing command: /home/pi/tbe/testSleep.sh
Here 1
Here 2
Here 3
Here $[70-1]
Command executed. Exit value: 0
This is really weird. Any pointer would be very helpful to me.

It seems that the shell executing the command is not same as that you are using to run the script on command line. Specify the shell as bash.
Add shebang in the script (as first line). It is always a good practice to be specific about the shell in the script
#!/bin/bash
You could also specify the shell you want to use for the shell script
String[] command = {"/bin/bash", "/home/pi/tbe/testSleep.sh"};

I ran your script in Ubuntu:
$ sh script.sh
Here 1
Here 2
Here 3
Here $[70-1]
script.sh: 8: [: Illegal number: $[70-1]
Apparently $[70-1] is not being evaluated but simply treated as a literal...
I saw the comments after I saved. They are correct. Using bash (I was lazy) gives the correct results.

Related

Java Runtime exec() does not resolve environment variable

If I run the following in a terminal I get the expected 123
$ /bin/sh
$ FOO=123
$ echo $FOO
123
Now I try to do the following with Java's Runtime's exec():
String[] envp = { "FOO=123" };
String cmd = "echo $FOO";
Process p = Runtime.getRuntime().exec(cmd, envp);
java.io.BufferedReader reader =
new java.io.BufferedReader(
new java.io.InputStreamReader(p.getInputStream()
)
);
System.out.println(reader.readLine());
I expect to see 123 but instead I get $FOO.
What am I missing?
The following works under Windows.
String[] envp = { "FOO=123" };
String cmd = "cmd /c echo %FOO%";
Process p = Runtime.getRuntime().exec(cmd, envp);
p.waitFor();
java.io.BufferedReader reader =
new java.io.BufferedReader(
new java.io.InputStreamReader(p.getInputStream()
)
);
String line;
while((line = reader.readLine()) != null) {
System.out.println(line);
}
What am I missing?
Firstly,
$ FOO=123
sets a shell variable. It is local to the shell. If you want a variable to be in the environment that child processes see, you must export it.
$ export FOO=123
But that's not the problem.
The real issue is the command string "echo $FOO". The problem is that $FOO is shell syntax .... but when you run a command from Java using exec:
exec itself doesn't understand shell syntax, and
exec doesn't run the command in a shell.
So the parameter that is given to the echo command consists of the literal string $FOO ... and that is what it outputs.
There are three approaches to solving this:
Interpolate the variable in Java; e.g.
String[] cmd = {"echo", "123"};
Process p = Runtime.getRuntime().exec(cmd);
or by doing repeated search / replace for things that look like variables. (But this only deals with environment variable interpolation, not other forms of shell substitution.)
Assuming that you are doing something more complicated than echo, write the command that you are running to do its own interpolation of environment variables. (This is clunky ...)
Explicitly invoke the command in a shell; e.g.
String[] envp = {"FOO=123"};
String[] cmd = {"/bin/sh", "-c", "echo $FOO"};
Process p = Runtime.getRuntime().exec(cmd, envp);
Note that you can use any shell, and provide pretty much any shell-ism that can be expressed in a single shell command line.

Run shell script with Angular CLI commands from Java

I'm trying to run a shell script from Java (using Runtime.getRuntime().exec(cmd)). All commands in the script file seem to be running normally except the angular-cli (ng) commands.
My Java File:
System.out.println("Executing Script...");
final String[] cmd = new String[]{"/bin/bash", "test.sh"};
final Process process = Runtime.getRuntime().exec(cmd);
process.waitFor();
final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String s;
while ((s = reader.readLine()) != null) {
System.out.println("Script output: " + s);
}
process.destroy();
System.out.println("Script Executed.");
test.sh:
#!/bin/bash
cd ~/ &&
ng new newAngularProject &&
Outout:
Executing Script...
Script Executed.
No errors are thrown. All other commands work but for some reason, I'm unable to run ng commands. Also, I've tested the file w/o running it from Java - When I run the same script directly on the console, it works perfectly and all commands (including ng commands) work neatly. I'm running on MacOS in case you wanted to know.
Also print the error stream. You will get the error message, if it is there.
final BufferedReader errorReader = new BufferedReader(new InputStreamReader(process.getErrorStream()));
while ((s = errorReader.readLine()) != null) {
System.out.println("error: " + s);
}
Also you can try to use absolute path of ng in your test.sh e.g. /home/my/install/node-vxxx/ng, since the process spawn by java to run your command might not get the environment variable you set in your .bashrc /.bash_aliases

Run exec file using Java on Mac

I need to start a server using bash, so I had created an UNIX shell , but I am not able to execute it with Java from Eclipse.
I tried the following code which doesn't work :
Process proc = Runtime.getRuntime().exec(./startServer);
Here is content of the startServer file :
#!/bin/bash
cd /Users/sujitsoni/Documents/bet/client
npm start
You can try the following two options.
Option 1
Process proc = Runtime.getRuntime().exec("/bin/bash", "-c", "<Abosulte Path>/startServer");
Option 2
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", "<Absolute Path>/startServer");
pb.directory(new File("<Absolute Path>"));
Process proc = pb.start();
A couple Of things can go wrong:
The path to the file you have given might be wrong for eclipse it can take relative path but from the command line, it will take the absolute path.
error=13, Permission denied - If the script file doesn't have required permissions. In your scenario, that might not the case as you are not getting any error.
At last, you are executing the script by java program so the output of your script will not be printed out. In your scenario, this might be the case. You need to capture the output of script from BufferedReade and print it. ( In your case server might have started but you are not seeing the logs/output of the script.
See the code sample below for printing output.
public static void main(String[] args) throws IOException, InterruptedException {
Process proc = Runtime.getRuntime().exec("./startServer");
proc.waitFor();
StringBuffer output = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(proc.getInputStream()));
String line = "";
while ((line = reader.readLine()) != null) {
output.append(line + "\n");
}
System.out.println(output);
}

Java with shell Script

I am writing a Java program from which I am executing a shell script. The shell script is calling another shell script. I am trying to print output returned by child script to parent shell script.
Below is my code.
public class App
{
public static void main( String[] args ) throws IOException, InterruptedException
{
String command = new String("/home/Test.sh");
Runtime rt = Runtime.getRuntime();
Process process = rt.exec(command);
process.waitFor(1, TimeUnit.MINUTES);
BufferedReader reader = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String s;
while ((s = reader.readLine()) != null) {
System.out.println("Script output: " + s);
}
Shell Script: Test.sh
#!/bin/bash
result=$( bash myscript.sh )
echo "$result"
myscript.sh
#!/bin/bash
echo "50"
I am getting empty output. I initial thought it might be because the Java process is not waiting for the shell script to finish. So added waitFor() but still no use. Can some one kindly help.
try this; this is not waiting problem.
#!/bin/bash
result=$( bash /home/myscript.sh ) # full path of myscript
echo "$result"
Also handle bash error as below;
public static void main(String[] args) throws IOException {
String command = new String("/tmp/1/Test.sh");
Runtime rt = Runtime.getRuntime();
Process process = rt.exec(command);
BufferedReader reader = new BufferedReader(new InputStreamReader(
process.getInputStream()));
String s;
while ((s = reader.readLine()) != null) {
System.out.println("Script output: " + s);
}
BufferedReader stdError = new BufferedReader(new
InputStreamReader(process.getErrorStream()));
System.out.println("Here is the standard error\n");
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
adduser tests;
1-
myscript.sh:
#!/bin/bash
adduser test
echo "50"
java console output;
Script output: 50
Here is the standard error of the command (if any):
adduser: Only root may add a user or group to the system.
2-
myscript.sh:
#!/bin/bash
sudo adduser test
echo "50"
java console output;
Script output: 50
Here is the standard error of the command (if any):
sudo: no tty present and no askpass program specified
3-
myscript.sh:
#!/bin/bash
echo -e "YOURPASSWORD=\n" | sudo -S adduser -shell /bin/bash --home /home/test test
echo -e "YOURPASSWORD\n" | sudo deluser --remove-home test
echo "OK"
java console output;
Script output: Adding user `test' ...
Script output: Adding new group `test' (1002) ...
Script output: Adding new user `test' (1001) with group `test' ...
Script output: Creating home directory `/home/test' ...
Script output: Copying files from `/etc/skel' ...
Script output: Try again? [y/N] Changing the user information for test
Script output: Enter the new value, or press ENTER for the default
Script output: Full Name []: Room Number []: Work Phone []: Home Phone []: Other []: Is the information correct? [Y/n] Looking for files to backup/remove ...
Script output: Removing files ...
Script output: Removing user `test' ...
Script output: Warning: group `test' has no more members.
Script output: Done.
Script output: OK
Here is the standard error of the command (if any):
[sudo] password for ..: Enter new UNIX password: Retype new UNIX password: passwd: Authentication token manipulation error
passwd: password unchanged
Use of uninitialized value $answer in chop at /usr/sbin/adduser line 563.
Use of uninitialized value $answer in pattern match (m//) at /usr/sbin/adduser line 564.
Use of uninitialized value $answer in chop at /usr/sbin/adduser line 589.
Use of uninitialized value $answer in pattern match (m//) at /usr/sbin/adduser line 590.

Java: Run multiple shell commands?

OK. I've been looking everywhere on how to execute multiple commands on a single command prompt from java. What i need to do is this, but not in command line, in code.
Execute:
cd C:/Android/SDK/platform-tools
adb install superuser.apk
..Basically i want to run adb commands from a program!!! Here is my java code so far:
MainProgram.java
public class MainProgram {
public static void main(String[] args) {
CMD shell = new CMD();
shell.execute("cmd /K cd C:/Android/SDK/platform-tools"); //command 1
shell.execute("cmd /C adb install vending.apk"); // command 2
}
}
CMD.java
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class CMD {
CMD() {
}
// THIS METHOD IS WHERE THE PROBLEM IS
void execute(String command) {
try
{
Process p = Runtime.getRuntime().exec(command);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
// read the output from the command
String s = null;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
catch(Exception e){
e.printStackTrace();
}
}
}
So what happens is...i can run the first command, but that cmd terminates and when i execute the 2nd command, a new cmd is created, hence i get an error because im not in the right directory. I tried a single string command "cmd /C cd C:/blablabla /C adb remount", but that just froze up...
Essentially, command 1 is executed and terminated, then command 2 is executed and terminated. I want it to be like this: command 1 executed, command 2 executed, terminated.
Basically i'm asking how can i run both of these commands in a row on a single command prompt???
My final target is to have a JFrame with a bunch of buttons which execute different adb commands when clicked on.
Easiest way is to make a batch file then call that from program
of course you could just say
C:/Android/SDK/platform-tools/adb install superuser.apk
there's no need to cd to a file if you name it directly
although what you are looking for is already made in ddms.bat which provides a complete visual link to adb
Create file as something.bat and set the contents to:
cd C:/Android/SDK/platform-tools
adb install superuser.apk
Then call:
Process p = Runtime.getRuntime().exec("something.bat");
all commands in the bat file are executed.

Categories

Resources