I am writing a java program that takes command and run it in unix shell. I have managed to get the output, but I need the program to detect if the given command is invalid, now, if I put in an invalid command, it gives me an error. Otherwise, it's working fine. Can anybody help me with this?? Here is my code:
public class TestCommand {
public static void main(String[] args) {
TestCommand obj = new TestCommand();
String sentence ="";
Scanner scn = new Scanner(System.in);
while (sentence != " ")
{
if (sentence !="exit")
{
System.out.println("> ");
sentence = scn.nextLine();
String outPut = obj.executeCommand(sentence);
System.out.println(outPut + "\n");
}
else
{
System.exit(2);
}
}
}
private String executeCommand(String sentence)
{
StringBuffer output = new StringBuffer();
Process p;
try
{
p = Runtime.getRuntime().exec(sentence);
p.waitFor();
BufferedReader bfrd = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = bfrd.readLine())!= null)
{
output.append(line);
}
bfrd.close();
}
catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
Unix shell language is extraordinarily complex. Re-implementing enough of it in java to test for correctness would be a large undertaking. If you just want to find out if some shell code is syntactically correct, you can use bash with the -n option:
bash -n file_with_code_to_test
Or:
bash -n -c string_with_code_to_test
The key thing here is the -n option. It tells bash to read the commands and check their syntax without executing them. Thus, this is safe to run.
You can run these command from java just as you would other bash commands.
bash will return an exit code of 0 if the code is syntactically correct. If it isn't, it will print error messages and return an exit code of 1.
Just to be clear, this checks syntax. It will, for example, not test for the existence of needed files or commands, only that the code is would run if they did exist.
Related
Environment: Windows 10 (Java) -> Windows 10 (PowerShell and C#)
Java: 1.8.0_252
Trying to remotely execute a C# program via PowerShell from Java. Seem to be having issues with the path. The C# program is in a subdirectory under a shared drive.
import java.io.*;
public class CallCSharp {
public static void main(String[] args) {
try {
ProcessBuilder builder = new ProcessBuilder("powershell.exe", "/c",
"\\SharedDrive\\Data\\Bin\\Program.exe \\\\10.1.1.1 -u user -p password");
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);
}
} catch (Exception e){
e.printStackTrace();
}
}
}
The error returned is
The term '\SharedDrive\Data\Bin\Program.exe' is not recognized as the name of a cmdlet, function, script file, or operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try again.
The path is correct and the C# program can be run successfully.
Suspect I am not formatting the ProcessBuilder call correctly.
I'd like to know whether a certain application is in focus in Linux. Say it is Google Chrome. To do so, I wrote a bash on-liner which does it correctly.
xdotool search --name --class 'google-chrome' | grep $(xdotool getactivewindow)
When this command is run in terminal, it will print the id of the terminal itself. To avoid that, run the following command and select Chrome in the three seconds time span.
sleep 3; xdotool search --name --class 'google-chrome' | grep $(xdotool getactivewindow)
The problem is that when I run the above-mentioned one-liner from Java, it seems to always print nothing. Here's my code:
String cmd = "xdotool search --name --class 'google-chrome' | grep $(xdotool getactivewindow)";
Process p = Runtime.getRuntime().exec(cmd);
String result = getCommandResult(p.getInputStream());
private static String getCommandResult(InputStream stream) throws IOException {
StringBuilder sb = new StringBuilder();
try (InputStreamReader isr = new InputStreamReader(stream);
BufferedReader in = new BufferedReader(isr)) {
String line;
while ((line = in.readLine()) != null) {
sb.append(line);
}
}
return sb.toString().trim();
}
I'm open to different solutions to resolving this problem.
As barti_ddu said, this is not working because of the pipe in the command. You can workaround this by creating one sh process with your command passed as the argument:
String cmd = "xdotool search --name --class 'google-chrome' | grep $(xdotool getactivewindow)";
Process p = new ProcessBuilder("sh", "-c", cmd).start();
String result = getCommandResult(p.getInputStream());
If You are using pipe redirection, then You either have to invoke the shell, or redirect the output from one program to another yourself.
However, IMHO, You do not need grep at all, just:
Enumerate windows of certain class.
Get the active window id and check if the active window list contains it.
Example (q&d, resource/error handling omitted):
private static List<String> exec(String... args) throws IOException {
List<String> result = new ArrayList<>();
String line;
BufferedReader reader = new BufferedReader(
new InputStreamReader(
new ProcessBuilder()
.command(args)
.start()
.getInputStream()));
while ((line = reader.readLine()) != null) {
result.add(line);
}
return result;
}
public static void main(String[] args) {
try {
Thread.sleep(3000);
String windowId = exec("xdotool", "getactivewindow").get(0);
System.out.println(windowId);
List<String> windowList = exec("xdotool", "search", "--name", "--class", "google-chrome");
System.out.println(windowList.contains(windowId));
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
Why are you hard coding the command into your class? Rather put your command in a shell script and call that instead. Then you have the flexibility to change the command without having to re-compile.
Process proc = Runtime.getRuntime().exec("./opt/scripts/myscript.sh");
... depending on your application, it would potentially be even better to pass in the shell script as parameter.
private void runCommandLine(String script) {
try {
Process proc = Runtime.getRuntime().exec(script);
proc.waitFor();
int character;
while((character = proc.getInputStream().read()) != -1) {
System.out.write(character);
}
while((character = proc.getErrorStream().read()) != -1) {
System.err.write(character);
}
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
}
EDIT:
If you goal is to figure out what window is currently in focus, then instead of trying to execute something via the command line, you could just use the JNA (Java Native Access) libraries to potentially do this.
Find out what application (window) is in focus in Java
Java Native Access (Github)
I am sending some greek text ("αλεξ") to my python program and I expect to get a popup window showing "αλεξ" but instead I get "αλεξ". Then I print the text parsed in and get it back to my java program, the result is "αλεξ" again! I am assuming the problem is the charset on my python program but I read somewhere that python3 uses by default utf-8.
Here is my Java Program :
public void run() {
try {
Runtime rt = Runtime.getRuntime();
String commands = "python -u C:\\Users\\Alex\\Desktop\\PythonProjects\\inputOutput.py";
Process proc = rt.exec(commands);
// read from terminal of the program
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream(),Charset.forName("UTF-8")));
// write on the terminal of the program
BufferedWriter out = new BufferedWriter(s=new OutputStreamWriter(proc.getOutputStream(), "UTF-8"));
System.out.println(s.getEncoding());
boolean telegramStarted = false;
String s;
while ((s=in.readLine())!=null) {
System.out.println(s);
if (telegramStarted |s.equals("started")) {
out.write("αλεξ");
out.newLine();
out.flush();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
Here is the Python Script :
import ctypes
print('started')
while True :
name = input('Enter your name: ')
ctypes.windll.user32.MessageBoxW(0, name, "Greetings", 1)
print('Hello', name, '!')
I executed the ldapsearch command through java. See the below code.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
public class TestMain
{
public static void main(String[] args) throws InterruptedException, IOException
{
String ldspCmd ="ldapsearch -ZZ -h ldap-url.com -x -D cn=username,ou=webapps,ou=ec,o=uoa -w $(echo PassWord | base64 -di) -b ou=ec_users,dc=ec,dc=auckland,dc=ac,dc=nz \"(groupMembership=cn=bpmusers,ou=ec_group,dc=ec,dc=auckland,dc=ac,dc=nz)\"";
String output = executeCommand(ldspCmd);
System.out.println(output);
}
private static String executeCommand(String command) {
StringBuffer output = new StringBuffer();
Process p;
try {
p = Runtime.getRuntime().exec(command);
p.waitFor();
BufferedReader reader =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
BufferedReader errorReader =
new BufferedReader(new InputStreamReader(p.getErrorStream()));
String erroLine = "";
while ((erroLine = errorReader.readLine())!= null) {
output.append(erroLine + "\n");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
}
But I get the error "ldapsearch: unable to parse debug value "i)"".
But when I execute the same command through command line it executes correctly and returns the records.
What am I doing wrong here? Can anyone help me to sort this?
Constructs like $(echo PassWord | base64 -di) inside your argument list are interpreted and handled by your shell. And when you invoke a command from Java using Runtime.exec, you are not using a shell, you are passing the command directly to the operating system, so you don't get the benefit of the shell interpreting these constructs.
If you want those benefits, you need to explicitly invoke the shell.
Also, Java doesn't have the same complex logic to split arguments to a command that a shell does. Java just cuts the argument list at space characters.
So in your executeCommand method you have a line:
p = Runtime.getRuntime().exec(command);
You should change that to:
// Add shell invocation around the above command
String[] shellCommand = { "/bin/bash", "-c", command };
p = Runtime.getRuntime().exec(shellCommand);
I am developing a Java application which will execute a console command. What the command actually does is, it will make changes to a file, then will save a copy of it with a different name to a different folder (both of the file and the output folder is specified by the user). And it requires some binary program to do this, which is a local resource of my application.
So my code is something like:
...
public void actionPerformed(ActionEvent e) {
File selectedFile = jFileChooser1.getSelectedFile();
File pathAssigned = jFileChooser2.getSelectedFile();
String file = selectedFile.getAbsolutePath();
String output = pathAssigned.getAbsolutePath();
String name = selectedFile.getName();
// What's next???
}
And the usage/syntax of the command is something like:
"command -options /package/binary.bin "+file+" "+output+"\\"+name+"-changed"
So my question would now be; What will be my next code? Should I use a Runtime? If so, then how?
And about including a local resource path to a command, does my syntax is correct?
I am still a newbie here as well as in Java programming so please be kind to your answers/comments. Thanks!
PS. The command is a platform independent by the way.
I hope the code below can help you. First you have a shell script that takes parameters.
#!/bin/bash
echo "hola"
echo "First arg: $1"
echo "Second arg: $2"
You save it in e.g. /home/dac/proj/javatest2016/src/main/java/myshellScript.sh and then you can pass the parameters from your Java code.
import java.io.*;
public class Main {
public static void main(String[] args) throws Exception {
try {
ProcessBuilder pb = new ProcessBuilder("/home/dac/proj/javatest2016/src/main/java/myshellScript.sh", "myArg1", "myArg2");
pb.directory(new File("/home/dac/proj/javatest2016/src/main/java"));
Process p = pb.start();
StringBuffer output = new StringBuffer();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
while ((line = reader.readLine())!= null) {
output.append(line + "\n");
}
System.out.println("### " + output);
} catch (Throwable t) {
t.printStackTrace();
}
}
}
Test
### hola
First arg: myArg1
Second arg: myArg2