I have a java application that downloads a file from a web service using wget. When executing the command through java it returns with: "wget: not an http or ftp url:"
When i execute the command directly it runs without problems. Here is my code:
try {
Debug.println("Starting copy of "+srcFile+" to "+destFile);
String command = "wget -O " + destFile + " \""+ srcFile +"\"";
Process p = Runtime.getRuntime().exec(command);
int exitCode = p.waitFor();
if(Debug.isDebugMode())
{
Debug.println(command);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String s;
while((s = stdInput.readLine()) != null)
{
Debug.println(s);
}
}
Debug.println("Finished with code: " + String.valueOf(exitCode));
}
catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
And this is the output:
24/04/2013 10:11:05 Starting copy of stoppenmetroken.webcolors.local/service/track?track=3b1ac68a288345c183a08c714901a398&mac=089000A09090 to /opt/byato/data/song/3b1ac68a288345c183a08c714901a398
24/04/2013 10:11:05 wget -O /opt/byato/data/song/3b1ac68a288345c183a08c714901a398 "stoppenmetroken.webcolors.local/service/track?track=3b1ac68a288345c183a08c714901a398&mac=089000A09090"
24/04/2013 10:11:05 wget: not an http or ftp url: "http://stoppenmetroken.webcolors.local/service/track?track=3b1ac68a288345c183a08c714901a398&mac=089000A09090"
24/04/2013 10:11:05 Finished with code: 1
ps: i removed the http:// part of the output because i dont have enough reputation points -.-
What am i missing?
Can you try to execute the command like this :
Process p = Runtime.getRuntime().exec("/bin/bash -c "+command); //for linux
or
Process p = Runtime.getRuntime().exec("cmd.exe /c "+command); //for Windows
Sometimes we need to explicitly invoke Linux shell or command prompt.
Hope this will work.
I suspect this:
String command = "wget -O " + destFile + " \""+ srcFile +"\"";
is the problem. When you run in a shell, the quotes around the URL will be removed. However when you run via Java you're not running via a shell and your URL starts with "http... (look closely at the error message).
If you don't want Runtime.exec() to parse and split your arguments then you might consider the variant that takes individual arguments. A more efficient solution still would be to download using HttpComponents.
Related
I'm writing a Java method to run a local bash script using Eclipse. The code is showing as below:
public static void setUp() throws IOException, InterruptedException {
Runtime rt = Runtime.getRuntime();
Process p;
String filePath = new File("").getAbsolutePath();
filePath = filePath.concat("/path/to/the/script");
String command = String.format("sh %s/setUp.sh", filePath);
System.out.println(command);
try {
p = rt.exec(command);
final int errorValue = p.waitFor();
if (errorValue != 0) {
System.out.println("error detected!");
InputStream error = p.getErrorStream();
BufferedReader br = new BufferedReader(new InputStreamReader(error));
String line = "";
while ((line = br.readLine()) != null) {
System.out.println(line);
}
p.destroy();
}
} catch (Exception e) {
e.printStackTrace();
}
}
AND the bash file is very simple:
#!/bin/bash
#create a local db and import some data
createdb -U dummy -O dummy -h localhost dbname
psql -h localhost -d dbname --file $1
The issue is
line 4: createdb: command not found
line 5: psql: command not found
I can run the script in terminal and I can copy line4 and line5 in terminal, and I can run mvn exec command in the terminal to run the method. All works.
Only thing not working is it was executed in eclipse.
I'm open to any opinion or advices, please let me know if you need more information.
Thanks for all the helps in advance!
I suspect that the Runtime that is used to execute the script won't have the paths set correctly. Try using full paths for the commands in the script, and see if that works (you can find the full paths by running which createdb and which psql in the terminal).
Here's the situation. Im creating a UI which will allow make using a genetic programming system (ECJ) easier to use.
Currently you need to run a command prompt within the ECJ folder and use the commands similar to this to execute a parameter file.
java ec.Evolve -file ec\app\tutorial5\tutorial5.params
Where the full path of tutorial5 is
C:\Users\Eric\Documents\COSC\ecj\ec\app\tutorial5\tutorial5.params
and the command prompt must be executed from
C:\Users\Eric\Documents\COSC\ecj
My program makes the user select a .params file (which is located in a ecj subdirectory) and then use the Runtime.exec() to execute
java ec.Evolve -file ec\app\tutorial5\tutorial5.params
What i have so far
// Command to be executed
String cmd = "cd " + ecjDirectory;
String cmd2 = "java ec.Evolve -file " + executeDirectory;
System.out.println(cmd);
try {
Process p = Runtime.getRuntime().exec(
new String[]{"cmd.exe", "/c", cmd, cmd2});
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
statusTF.append(r.readLine());
p.waitFor();
} catch (IOException | InterruptedException ex) {
System.out.println("FAILED: " + ex.getMessage());
statusTF.append("Failed\n");
}
Currently it outputs the change directory command but nothing else.
Can this be done?
First, the 'cd' command can't be executed by Runtime.exec() in the first place (see How to use "cd" command using Java runtime?). You should be able to just set the working directory for the process when you call exec (see below).
Second, running 'cmd.exe /c' to execute your process isn't what you want here. You won't be able to get the results of your process running, because that is returned to the command window -- which eats the error and then closes without passing the error along to you.
Your exec command should look more like this:
Process p = Runtime.getRuntime().exec(
command, null, "C:\Users\Eric\Documents\COSC\ecj");
Where 'command' looks like this:
String command = "java ec.Evolve -file ec\app\tutorial5\tutorial5.params"
Edit: For reading error messages, try this:
String error = "";
try (InputStream is = proc.getErrorStream()) {
error = IOUtils.toString(is, "UTF-8");
}
int exit = proc.waitFor();
if (exit != 0) {
System.out.println(error);
} else {
System.out.println("Success!");
}
You can use Java processbuilder:
processBuilder documentation!
you can define the working directory of the process and all other stuff.
Each call to exec() runs in a new environment, this means that the call to cd will work, but will not exist to the next call to exec().
I prefer to use Apache's Commons Exec, it's provides an excellent facade over Java's Runtime.exec() and gives a nice way to specify the working directory. Another very nice thing is they provide utilities to capture standard out and standard err. These can be difficult to properly capture yourself.
Here's a template I use. Note that this sample expects an exit code of 0, your application may be different.
String sJavaPath = "full\path\to\java\executable";
String sTutorialPath = "C:\Users\Eric\Documents\COSC\ecj\ec\app\tutorial5\tutorial5.params";
String sWorkingDir = "C:\Users\Eric\Documents\COSC\ecj";
try (
OutputStream out = new ByteArrayOutputStream();
OutputStream err = new ByteArrayOutputStream();
)
{
// setup watchdog and stream handler
ExecuteWatchdog watchdog = new ExecuteWatchdog(Config.TEN_SECONDS);
PumpStreamHandler streamHandler = new PumpStreamHandler(out, err);
// build the command line
CommandLine cmdLine = new CommandLine(sJavaPath);
cmdLine.addArgument("ec.Evolve");
cmdLine.addArgument("-file");
cmdLine.addArgument(sTutorialPath);
// create the executor and setup the working directory
Executor exec = new DefaultExecutor();
exec.setExitValue(0); // tells Executor we expect a 0 for success
exec.setWatchdog(watchdog);
exec.setStreamHandler(streamHandler);
exec.setWorkingDirectory(sWorkingDir);
// run it
int iExitValue = exec.execute(cmdLine);
String sOutput = out.toString();
String sErrOutput = err.toString();
if (iExitValue == 0)
{
// successful execution
}
else
{
// exit code was not 0
// report the unexpected results...
}
}
catch (IOException ex)
{
// report the exception...
}
I have a batch file on windows machine.
The path to the same is having spaces in it. E.g. C:\Hello World\MyFile.bat
I am trying to execute the batch file through java as:
Runtime.getRuntime().exec(dosCommand + destinationFilePath + batch)
But, as the path has spaces, it says "C:\Hello" is not a valid command or directory.
I tried this too:
Complete command: cmd /c start /wait "C:/Hello World/MyFile.bat" It opens the command prompt, but does not go to the folder Hello World and does not execute the bat file
How do I handle this situation.
Let me know if any additional Info. is required.
Using quotation marks ("C:\Hello World\MyFile.bat") should do the trick. Within Java you'll have to secape the quotation marks with \ (String batch = "\"C:\Hello World\MyFile.bat\"").
I was able to solve it using ProcessBuilder.
The directory in which the bat file is present can be added to the working directory as:
processBuilder.directory(new File("C:\hello world\"));
This works like gem.
int result = 1;
final File batchFile = new File("C:\\hello world\\MyFile.bat");
final File outputFile = new File(String.format("C:\\hello world\\output_%tY%<tm%<td_%<tH%<tM%<tS.txt", System.currentTimeMillis()));
final ProcessBuilder processBuilder = new ProcessBuilder(batchFile.getAbsolutePath());
processBuilder.redirectErrorStream(true);
processBuilder.redirectOutput(outputFile);
processBuilder.directory(new File("C:\\hello world\\"));
try {
final Process process = processBuilder.start();
if (process.waitFor() == 0) {
result = 0;
}
System.out.println("Processed finished with status: " + result);
} catch (IOException | InterruptedException e) {
e.printStackTrace();
}
Did you try to escape quotes surrounding the path such as :
Runtime.getRuntime().exec(dosCommand + "\"" + destinationFilePath + batch + "\"")
I just solved this problem using a ProcessBuilder as well, however I gave the directory with a space to processBuilder.directory and ran the command with the bat file name.
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "start", "/wait", "export.bat");
pb.directory(new File(batDirectoryWithSpace));
pb.redirectError();
try {
Process process = pb.start();
System.out.println("Exited with " + process.waitFor());
}
catch (IOException | InterruptedException ex) {
Exceptions.printStackTrace(ex);
}
All,
I originally had a shell script that called SQLLoader (Oracles data upload tool).
The problem was that SQLLoader takes a plain text password as input so I decided to build a Java application to call SQLLoader internally passing a decrypted password into the command string.
e.g.
sqlldr user/pass#DBServer control=../sqlloader.ctl log=sqlloader.log data=mydata.csv
So with my java wrapper it became this in my shell script
java -jar sqlloader.jar sqlloader.ctl mydata.csv
However a new problem developed when SQLLoader complained there was no file to load. After some head scratching it was discovered that a subsequent command in my shell script seemed to be executing while my java application was still running. Therefore it was behaving asynchronously.
The next command was moving the input file sqlloader was using before it could get a chance to use it. So I put a sleep command in of 20 seconds to give my java application time to run.
java -jar sqlloader.jar sqlloader.ctl mydata.csv
echo $?
sleep 20
if [ $? -ne 0 ]
then
echo "SQLLoader failed during execution, please check the log : "
mv mydata.csv
else
echo "SQLLoader successfully processed file : "
mv mydata.csv
fi
Does anyone know why unix is behaving this way, does Java execute my SQLLoader as a different user/ thread?
This is my java code:
Runtime Rt;
Process Prc;
Prc = Rt.exec("sqlldr user/decryptedpass#DBServer control=../sqlloader.ctl log=sqlloader.log data=mydata.csv);
system.exit(0);
I checked the Runtime Class for anything about it being Asynchronous but couldnt find anything
http://docs.oracle.com/javase/7/docs/api/java/lang/Runtime.html
Any theories or suggestions?
Thanks
Yes. If you look at Runtime.exec again it does specify that it will launch a new process in the specified environment (e.g. independently of the current "environment" or as you put it asynchronously). You should use ProcessBuilder to create a Process and then waitFor that Process to finish before calling System.exit - which certainly isn't mandatory. Something like this
public static void main(String[] args) {
// String command = "/usr/bin/sleep 5";
List<String> command = new ArrayList<String>();
command.add("c:/cygwin/bin/sleep");
command.add("5");
ProcessBuilder pb = new ProcessBuilder(command);
BufferedReader is = null;
try {
System.out.println("Starting command " + command);
Process p = pb.start();
int ret = p.waitFor();
is = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = is.readLine()) != null) {
System.out.println(line);
}
if (ret == 0) {
System.out.println("Command has completed.");
System.exit(ret);
} else {
System.out.println("Command completed with return code " + ret);
System.exit(ret);
}
} catch (Exception e) {
System.out.println("Caught Exception " + e.getMessage()
+ " running command " + command);
e.printStackTrace();
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
System.out.println("COMMAND FAILED");
System.exit(1);
}
You need to wait for process completion, you should also read all output (stdout and stderr) from the process you are starting.
If you call exit() after exec(), Java will do just that - exit immediatedly.
Here is an article that explains Runtime.exec pitfalls: http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html?page=4 (also consider the other pages).
I've been trying to make it where I can download a .exe file from the web, read it, and write it to a file locally, and then execute.
URL url = new URL("http://www.ddlands.com/downloads/Calc.exe");
URLConnection c = url.openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(c.getInputStream()));
String line = "";
File file = new File("analbread"+".exe");
BufferedWriter bw = new BufferedWriter(new FileWriter(file));
while((line = br.readLine()) != null){
bw.write(line + "\n");
}
br.close();
bw.close();
Process r = Runtime.getRuntime().exec("analbread" + ".exe");
System.out.println(r.toString());
System.out.println("WORKS!");
Although I know that doesn't work due to using BufferedWriter, and i'm not sure if it runs the exe.
For the downloading part, you'll need to use binary read/write. See this for further details: Working unbuffered streams.
For the executing part, the problem is that the Runtime.exec()-method can't launch your executable file.
At least under Linux (I can't test it on Windows), you'll need the full path to the executable file (or use ./[file] when the file is in the same directory as your application) to be able to execute it.
Only giving the command works for executables which are part of your systems PATH-variable.
Have a look at ClickOnce: http://en.wikipedia.org/wiki/ClickOnce
We've used that succesfully.
Ive used the following with good results to run command line scripts. You can create a batch script that runs the executable or run it directly using the exec method - probably pass "cmd ". This opens a command prompt from which you can run anything.
public static void runScript(String batchFile, boolean waitForExit0, int retryTime)
{
try
{
String runString = "cmd /c start " + (waitForExit0?"/wait ":"") + "/MIN " + batchFile;
Process p = Runtime.getRuntime().exec(runString); // /c start /wait
while (true)
{
try
{
int exit = p.exitValue();
if (exit == 0)
{
System.out.println("completed: " + runString);
return;
}
}
catch(Exception e)
{
String s = "";
}
Thread.sleep(retryTime);
}
}
catch(Exception e)
{
String s = "";
}
}