How to escape java special characters and run Linux commands - java

I'm writing a java program to find specific files(files with special permissions and by file type) within the directory. The following command executes properly since there aren't any special characters.
find /home/Cnf271/Desktop/ -perm -4000 ;
Now if i try to execute the following command using my java program, terminal doesn't give a proper result.
find /home/Cnf271/Desktop/ -name "*.txt" -perm -4000 -exec ls -ldb {} \;
Java Program,
//
..
System.out.print("Please enter directory path: ");
fileDirectory = scan.next();
System.out.print("Please enter file type (txt/pdf): ");
fileType = scan.next();
filetypecmd = " \"*." +fileType+ "\" ";
System.out.println(filetypecmd);
String cmd = "find "+fileDirectory+ " -name "+filetypecmd+" -perm -4000" ;
Runtime run = Runtime.getRuntime();
Process process = run.exec(cmd);
BufferedReader buffer = new BufferedReader(new InputStreamReader(process.getInputStream()));
String space = "";
while ((space=buffer.readLine())!=null) {
System.out.println(space);
..
//
Program works fine.however, String cmd command doesn't give me a proper result because linux command is wrapped with special characters.How do I execute the following command in my java program.
find /home/Cnf271/Desktop/ -name "*.txt" -perm -4000 -exec ls -ldb {} \;
Thanks.

Elements that need to be quoted (or escaped special characters) for a Linux command shell do not need to be quoted when being executed by Runtime.exec() (they do not need to be protected from the shell).
In your code, remove the extra quotes on the wildcard search parameters:
String filetypecmd = " *." + fileType + " ";
I tested this and was able to run your code correctly on Linux, but I had to remove your -perm -4000 parameters to get results in my case. I received no results with the extra quotes around "*.txt" but all was well without them.
By the way, you can also use a Scanner to collect the results:
Scanner results = new Scanner(process.getInputStream());
while (results.hasNextLine())
{
System.out.println(results.nextLine());
}

Related

Execute cmd script with double quotes

Im trying to execute a Process with multiple parameters but they have double quotes "..." .
This is how I build the script:
public void capture(String from, String to, String outputFile)
This method will run the command, it takes the 3 parameters which are given here:
capture("0", "100", "C:\\Program Files\\myProgram\\file.txt")
So the full built command looks like this:
String command = "\"C:\\Program Files (x86)\\otherProg\\prog.exe\" /dothis "
+ from + " " + to + " \"" + outputFile + "\"";
To see it clearly, this is the visual output of the command:
"C:\Program Files (x86)\otherProg\prog.exe" /dothis 0 100 "C:\Program Files\myProgram\file.txt"
Ok, and then I execute it like this:
String[] script = {"cmd.exe", "/c", command};
Process p = Runtime.getRuntime().exec(script);
And at this point nothing happens.
The command doesnt get executed, however if I take the output:
"C:\Program Files (x86)\otherProg\prog.exe" /dothis 0 100 "C:\Program Files\myProgram\file.txt"
Copy-paste it in CMD the command DOES get executed (and i get the expected output).
I have tried building the command like this but same effect happens.
The only possible way to run that command is to do it like this:
"C:\Program Files (x86)\otherProg\prog.exe" /dothis 0 100 C:\Folder\myProgram\file.txt
without the quotes on last parameter and of course, without spaces in the route.
What is the solution to this?
Update 1:
Also tried script = script.replace("\n","").replace("\t","") and neither works.
Update 2:
Just tried building the process like this:
Process p = Runtime.getRuntime().exec(
"\"C:\\Program Files (x86)\\otherProg\\prog.exe\" /dothis 0 100 \"C:\\Program Files\\myProgram\\file.txt\"");
Passing the escaped command straight to the process does work, but why doesnt it work when they are parameters and building string with them?
SOLVED THANKS TO Tim Biegeleisen below
As he mentioned, there is a problem for java to make a difference between command and parameter and when to run multiple commands, to solve this do the next:
String command = "cd \"C:\\Program Files (x86)\\otherProgram\\\" & program.exe /capture "+from+" "+to+" \""+outputFile+"\"";
& does it work.
I am posting this mainly for informational purposes. Consider the following code:
Process p = Runtime.getRuntime().exec("cmd /c start cmd.exe echo Hello World");
This will indeed cause a Command Prompt to appear at my home (default) directory, but it will not actually execute the echo command. In fact, the following will do the same:
Process p = Runtime.getRuntime().exec("cmd /c start cmd.exe blah blah blah");
So it seems that Java is ignoring everything which comes after the cmd.exe. My explanation for this is that the actual command is start, and the parameter to that command is cmd.exe. In other words, once Java has launched the Command Prompt, it has already used the parameter, and everything else is ignored.
This observation is consistent with your findings that the following works:
Process p = Runtime.getRuntime().exec(
"\"C:\\Program Files (x86)\\otherProg\\prog.exe\" /dothis 0 100 \"C:\\Program Files\\myProgram\\file.txt\"");
In this case, the command is prog.exe, and what comes after it are the parameters. However, if you had tried piping your command into Command Prompt and running from there, then it would not have worked.
So it seems that using Runtime.getRuntime().exec() allows you to execute one process from Java, but not two of them. This makes sense, since Java can execute a process, but the API does not allow it to launch a second process from the first one.
Try to use the process builder and / or seperate your arguments
Process Builder
ProcessBuilder pb = new ProcessBuilder("\"C:\\Program Files (x86)\\otherProg\\prog.exe\"", "/dothis ", "from + " " + to + " \"" + outputFile + "\"");
Process p = pb.start();
Runtime
Runtime.getRuntime().exec(new String[]{"\"C:\\Program Files (x86)\\otherProg\\prog.exe\"", "/dothis ", "from + " " + to + " \"" + outputFile + "\""});

"Cannot run program" when using Runtime.exec with spaces in program filename

I am using the below code to open the "sample.html' file.
String filename = "C:/sample.html";
String browser = "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe";
Runtime rTime = Runtime.getRuntime();
Process pc = rTime.exec(browser + filename);
pc.waitFor();
However, I am getting the below error.
java.io.IOException: Cannot run program "C:/Program": CreateProcess error=2, The system cannot find the file specified
Could someone please help me figure this. Thanks in advance.
Runtime.exec(String) automatically splits the string at spaces, assuming the first token is the command name and the rest are command line parameters. Also you do not have a space between browser and file, although that is not the root cause of the problem.
It thinks you want to run "C:/Program" with two command line arguments:
"Files"
"(x86)/google/Chrome/Application/chrome.exeC:/sample.html"
Use Runtime.exec(String[]) instead, that way you have full control over what is what:
String[] command = new String[]{browser, filename};
Runtime.exec(command);
Try this.
String filename = "C:\\sample.html";
String browser = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec(new String[] {browser, filename});
} catch (IOException e) {
e.printStackTrace();
}
Stop using Runtime.exec(String) - the problem is in how it processes the single string input.
The error message indicates how/where it is failing: note that it stops after "C:/Program" (or, the first space). This indicates that exec parsed the string "incorrectly" and thus isn't even looking for the correct executable.
Cannot run program "C:/Program"
Instead, consider the use of ProcessBuilder. While the usage is still system-dependent, ProcessBuilder allows separation of the executable file-name (and need to deal with it specially) and the arguments and does it's darnedest to invoke the target correctly.
String filename = "C:\\sample.html";
String browser = "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe";
ProcessBuilder pb = new ProcessBuilder(browser, filename);
// setup other options ..
// .. and run
Process p = pb.start();
p.waitFor();
From what I can tell, in Windows, ProcessBuilder will wraps the individual components in quotes; this can create a different problem when arguments contain quotes..
Parameters must be passed separately:
Process pc = rTime.exec(new String[]{browser, filename});
Using exec() is not like using the command line - you can not use spaces to delimit the command from its parameters. Your attempt would try to execute a command whose path was the concatenation of the exec and the filename as one giant string.

run bash commande by ssh using Java

I want to run a script with ssh from java. The script takes a number as parameter. I launch this code :
String myKey="/home/my_key.pem";
Runtime runtime = Runtime.getRuntime();
String commande = "ssh -i "
+myKey+" ubuntu#ec2-56-75-88-183.eu-west-1.compute.amazonaws.com './runScript.bash 8000'";
Process p = runtime.exec(commande);
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line = reader.readLine();
while (line != null) {
System.out.println(line);
line = reader.readLine();
}
p.waitFor();
I obtain this error :
bash: ./runScript.bash 8000: No such file or directory
The name of file is correct. chmod given to runScript.bash is 777.
When i run the command line directly from bash it works. But from IDE, it does not.
How can i do to run this commande line correctly please ?
The error makes it clear:
bash: ./runScript.bash 8000: No such file or directory
This indicates that the shell is trying to invoke a script called ./runScript.bash 8000 -- with the space and the 8000 in the filename of the script.
It's rare for me to be telling anyone to use fewer quotes, but, well, this is actually a case where that would fix things.
Better would be to avoid double evaluation altogether:
Runtime.exec(new String[] {
"ssh",
"-i", myKey,
"ubuntu#ec2-56-75-88-183.eu-west-1.compute.amazonaws.com",
"./runScript 8000"
})

Runtime.exec() to bash javac error

I'm using Runtime.exec() to run a shell script in a Java program.
The script basically compiles a java program and runs it and goes something like:
./run2.sh "/Users/user/Desktop/Test.java" "Test" "/Users/user/Desktop/"
my parameters in general are the absolute path of the java file, class name and directory where the supposedly compiled class file is
my script is simply
javac "$1"
cd "$3"
java "$2"
I've tried running the resulting command in my Terminal and it works fine. however when the java program runs it, I get and error:
javac: invalid flag: "/Users/user/Desktop/Test.java"
What should I do? I've tried every possible script I can find on the internet (*edit: and I can think of, of course)
(*edit: execute statement)
// some code here...
String[] outFile = translate.translate();
try {
String params = "";
for(String sss: outFile) {
String tmp = "\"" + sss + "\"";
params += tmp + " ";
}
String command = "./run2.sh "+params;
System.out.println(command);
Process proc = Runtime.getRuntime().exec(command);
} //respective catch
the first line, String[] outFile = translate.translate() returns an array Strings of my supposedly parameters
Your mistake is including quote characters in the command string that you are passing to exec(). The exec() method does NOT know how to deal with quotes or other "shell language" stuff. You would be better off trying to execute the command something like this:
Runtime.getRuntime().exec(new String[]{command, arg1, arg2, arg3});
where the command and arguments strings DO NOT have quotes around them.

Java IOException on exec call with any command-line arguments

I've got a java application that will eventually get fairly deep into external process integration, including IPC with those processes. For now though, what I'm trying to do is simply run a powershell script from java.
what I've got:
private void runPowershellScript() {
String command =
"" + "powershell" + " ";
// Paths.get("").toAbsolutePath() + "\\" + scriptFileName + " " +
// Paths.get("").toAbsolutePath() + "\\" + INPUT_FILE_NAME + " " +
// Paths.get("").toAbsolutePath() + "\\" + OUTPUT_FILE_NAME + "";
try {
ProcessBuilder builder = new ProcessBuilder(command);
builder.redirectErrorStream(true);
Process process = builder.start();
BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine ()) != null) {
System.out.println ("Stdout: " + line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
With what you see there, I get the Windows Powershell name and copyright coming out over that reader, but if I add any of the commented out lines (all of which resolve to proper paths, eg C:\Users\Geoff\Code\OPTIP\FakeProgram.ps1) I get:
java.io.IOException: Cannot run program "powershell C:\Users\Geoff\Code\OPTIP\FakeProgram.ps1 ": CreateProcess error=2, The system cannot find the file specified
I've tried a dozen different combinations of strong and weak quotes, and I've tried passing them as arguments to cmd.exe /c powershell ... but nothing I've tried runs the script. If there is a single space in the command string, I get an IO Exception.
I'm wondering if maybe it has something to do with character encoding? When I simply invoke powershell, I'm getting 'back from reader.readLine() is:
W\u0000i\u0000n\u0000 ... Which I presume is my IDE's (IntelliJ's) way of telling me its "Windows Powershell" with a null unicode character between each letter.
The Java ProcessBuilder documentation is a little vague on exactly what you can pass as arguments:
a command, a list of strings which signifies the external program file to be invoked and its arguments, if any. Which string lists represent a valid operating system command is system-dependent. For example, it is common for each conceptual argument to be an element in this list, but there are operating systems where programs are expected to tokenize command line strings themselves - on such a system a Java implementation might require commands to contain exactly two elements.
I dont know what that means. The command I'm trying to give it works from a CMD and Powershell window, and also from the windows run dialog.
gist containing the class of above method:
https://gist.github.com/Groostav/9c5913e6f4696a25430d
gist containing my powershell script:
https://gist.github.com/Groostav/347a283ac7ec6a738191
Thanks for any help.
You have to put the arguments in separate strings, not concatenating them to the powershell call as a single string.
Something like
new ProcessBuilder("Powershell", scriptFileName, INPUT_FILE_NAME);

Categories