I am developing a Linux-only Java application, and I need to execute a shell script in it. According to what I have read, the only way to execute that shell script is by extracting it from the jar file and executing it. The question is? How can I extract that shell script at runtime?
Thank you in advance
Unix does not know how to run scripts inside jar files. You must create a file (there are routines to create temporary files in the runtime) with the given content and then run that file - see How to run Unix shell script from Java code? for instructions. When done, delete it from the filesystem.
I found this question today ... i think there is a better answer:
unzip -p JARFILE SCRIPTFILE | bash
should do it.
where JARFILE is the path to the jar file
and SCRIPTFILE is the path WITHIN the jar of the script file to execute.
this will extract the file to stdout which is then piped to the shell (bash)
As someone has mentioned before, you can copy the content in the bundle resource to a temp location, execute the script, and remove the script in the temp location.
Here is the code to do that. Note that I am using Google Guava library.
// Read the bundled script as string
String bundledScript = CharStreams.toString(
new InputStreamReader(getClass().getResourceAsStream("/bundled_script_path.sh"), Charsets.UTF_8));
// Create a temp file with uuid appended to the name just to be safe
File tempFile = File.createTempFile("script_" + UUID.randomUUID().toString(), ".sh");
// Write the string to temp file
Files.write(bundledScript, tempFile, Charsets.UTF_8);
String execScript = "/bin/sh " + tempFile.getAbsolutePath();
// Execute the script
Process p = Runtime.getRuntime().exec(execScript);
// Output stream is the input to the subprocess
OutputStream outputStream = p.getOutputStream();
if (outputStream != null) {
outputStream.close();
}
// Input stream is the normal output of the subprocess
InputStream inputStream = p.getInputStream();
if (inputStream != null) {
// You can use the input stream to log your output here.
inputStream.close();
}
// Error stream is the error output of the subprocess
InputStream errorStream = p.getErrorStream();
if (errorStream != null) {
// You can use the input stream to log your error output here.
errorStream.close();
}
// Remove the temp file from disk
tempFile.delete();
Do not bundle the script in your jar in the first place. Deploy the scripts as independent files.
Related
I want to run a batch file using a java program, when I double click the .bat file it asks me to enter 'D' and after that it creates some folders in C drive, below is the contents of the .bat file:
xcopy "data" "C:\data" /S
xcopy "rapid" "C:\rapid" /S
subst x: /D
subst x: C:\
My Java code is as below:
try {
//C:\Desktop\Speed\view_R36_WD_Release\RAPID\switchToLive.Bat
String cmds[] = {"C:\\Users\\608521747\\Desktop\\Speed\\view_R36_WD_Release\\RAPID\\switchToDev.bat"};
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(cmds);
process.getOutputStream().close();
InputStream inputStream = process.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(inputStream);
BufferedReader bufferedrReader = new BufferedReader(inputstreamreader);
String strLine = "";
while ((strLine = bufferedrReader.readLine()) != null) {
System.out.println(strLine);
}
} catch (IOException ioException) {
ioException.printStackTrace();
}
its not giving me any errors but it neither ask me to enter any value nor it creates any folder.
I want to know what do I need to do in java code so that it will ask me to enter the 'D' and then the .bat file should continue in a normal flow.
Any help is appreciated.
Your code needs to specify which program to execute your .bat file with.
Start narrowing down with the following fix.
p = run.exec("cmd.exe /c " + cmds);
Also try this link for similar code for similar question previously answered here.
Batch files are not executable files. So you will need to run cmd.exe and pass the batch file as parameter.
Please refer to this post - it addresses the same issue and provides a good solution - How do I run a batch file from my Java Application?.
I am new to perl but have done some programming in java facing a problem in running the perl script present in the jar file .
I am using windows and I have written a perl script to convert one type of file to another type .
I have checked the perl script with the java program using the Runtime and I am able to run the same as required and i am getting the output converted files as well (using the cmd line)
I have created a GUI in java to get the files to convert to the target files . I am able to run the file from netbeans IDE as will .
But when I am trying to run the jar file .
I am using URL to get the URL to the perl script .
URL url = this.getClass().getResource("/com/MyProject/FileConverter/fileconverter.pl");
and Runtime for Executing the script :
String[] cmd = {"perl",path,input_file,output_file};
process = Runtime.getRuntime().exec(cmd);
Please help in resolving the issue . Basically i do need to know how we can run the perl script present in the same jar file that we are executing.
You will have to read that perl file as resource and write it somewhere on file system as File (like this) and then pass that path to your command
See Also
Extract and load DLL from JAR
I'm assuming you have your perl script file in you jar and you don't want to extract it, just execute it "from inside".
One solution is to get the "stream" of your "resource" (your perl script), and then execute "perl" writing your script in the process' standard input.
This is better explained with a piece of code:
IMPORTANT CAVEAT: the path to your script in getResourceAsStream shouldn't start with /
// Start the process "perl"
Process process = Runtime.getRuntime().exec("perl");
// get the script as an InputStream to "inject" it to perl's standard input
try (
InputStream script = ClassLoader.getSystemClassLoader()
.getResourceAsStream("com/MyProject/FileConverter/fileconverter.pl");
OutputStream output = process.getOutputStream()
) {
// This is to "inject" your input and output file,
// as there is no other easy way ot specify command line arguments
// for your script
String firstArgs = "$ARGV[0] = \"" + input_file + "\";\n" +
"$ARGV[1] = \"" + output_file + "\";\n";
output.write(firstArgs.getBytes());
// send the rest of your cript to perl
byte[] buffer = new byte[2048];
int size;
while((size = script.read(buffer)) != -1) {
output.write(buffer, 0, size);
}
output.flush();
}
// just in case... wait for perl to finish
process.waitFor();
I'm trying to unpack/extract an archive, which is supplied in my program, containing binaries.
The copy from within the jar to the file works just fine, but when I try to extract the zip, it returns unexpectedly and only copies half of a file, and ignores the other file completely.
Here's a bit more detailed description:
I'm trying to unzip an archive copied to a folder, from within the program's .jar.
The program I'm using to unzip is "unzip" (comes with Linux).
The command used to extract is:
unzip -o <file>.zip
which is exactly what I'm using in following code:
ProcessBuilder process = new ProcessBuilder();
process.command("unzip", "-o", adb_tools.toString());
process.redirectErrorStream(true);
Process pr = process.start();
String line;
BufferedReader processReader = new BufferedReader(new InputStreamReader(pr.getInputStream()));
while ((line = processReader.readLine()) != null)
log(Level.INFO, "Extracting Android Debugging Bridge: " + line, true);
log(Level.INFO, "Android Debugging Bridge has been extracted and installed to system. Marking files as executable...", true);
pr.destroy();
processReader.close();
When I use the command directly via the Terminal, everything works fine, both files are extracted and inflated, and are executable, however, as mentioned above, when I use the command in Java, only one file gets copied (and even that only goes half way), and the other file is completely ignored.
How can I fix this problem, and prevent this happening again, with different programs?
Thanks in advance!
If you need to do a common task in Java, there is always a library out there which does what you need better than yourself. So use an external library for unzipping. Check here:
What is a good Java library to zip/unzip files?
It looks like you can use zip4j like this (from djangofan's answer):
public static void unzip(){
String source = "some/compressed/file.zip";
String destination = "some/destination/folder";
String password = "password";
try {
ZipFile zipFile = new ZipFile(source);
if (zipFile.isEncrypted()) {
zipFile.setPassword(password);
}
zipFile.extractAll(destination);
} catch (ZipException e) {
e.printStackTrace();
}
}
I have written some code for executing .bat file. which contains some
commands like setting java classpath,etc..And finally there is one command
which runs a Java class file.The HelloWorld class converts some xml file and generating a new xml file in some folder. When I double click .bat file, it executes fine,
but when I try to run I am not getting any output as I was getting through
double click the .bat file. How to make a batch execute and probably it would be nice
if I could see the results through Java console.
Following is MyJava code to execute the .bat file
public void run2() {
try {
String []commands = {"cmd.exe","/C","C:/MyWork/Java/classes/run.bat"} ;
Process p = Runtime.getRuntime().exec(commands);
BufferedReader in = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line = null;
while ((line = in.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
And below the some commands which has been set to .bat file
set CLASSPATH=%CLASSPATH%;C:/MyWork/Java
set CLASSPATH=%CLASSPATH%;C:/MyWork/Java/classes
java -cp test.jar;test2.jar test.HelloWorld
Tried with "/C" commad as well. It does not execute. Actually it does not give effect of double click the .bat file. Is there any other way that I can try with?
I can see the contents inside the .bat file through Eclipse console. But it does not give the desired output. Desired output means when I double click .bat file, it executes well. But through java call, I can see the contents only .
When using cmd.exe use /C-Parameter to pass command:
String []commands = {"cmd.exe","/C","C:/MyWork/Java/classes/run.bat"} ;
according to this, the Windows CMD needs the /c argument, to execute commands like this. try this:
String []commands = {"cmd.exe","/c","C:/MyWork/Java/classes/run.bat"} ;
Windows uses \ backslash for Windows and MS-DOS path delimiter. Forward slash / is accepted by Java in the java.io package and translated to be a path delimiter, but will not be directly acceptable to Windows or accepted by the cmd.exe shell.
You may also need to specify either the working directory for the batch file to be executed in, or possibly a full path to the cmd.exe command interpreter.
See: Runtime.exec (String[] cmdarray, String[] envp, File dir)
String[] commands = {"C:\\Windows\\System32\\cmd.exe", "/c",
"C:\\MyWork\\Java\\classes\\run.bat"};
File workDir = new File( "C:/MyWork");
Process process = Runtime.getRuntime().exec( commands, null, workDir);
To verify if the batch file is run at all, add a pause command to the batch file. That will keep the window open so you can verify if the batch file is launched at all, and debug this stage-by-stage.
You do not read the error output of your batch file, therefore, you'll never see any error messages printed from there or from CMD.EXE itself. In addition, the sub-program may stall and just wait for you to read the error stream.
Please see related discussions here: How to make a java program to print both out.println() and err.println() statements?
this is what I want to do:
I need to start two jar Files from out of a java file and i want to call a method from the firstly started jar file, when i read a specific status from the second jar file. I figured out how to read the outsputstream from that jar files. (I also know, that its not the jar file who's printing out, but the classes inside the jar file. I just fomulated the question in this way to clearly explain that I use a java file in which I start two jar files)
long l = System.currentTimeMillis();
Process theProcess1 = Runtime.getRuntime().exec("java -jar \"C:/test.jar\"");
inStream = new BufferedReader(new InputStreamReader( theProcess1.getInputStream() ));
...
I can now read the jar file's output.
On a special keyword I want the firstly started jar to run a certain method (non static).
e.g.:
if(theProcess2 output a certain statuscode)
{
start a certain Method from executed jar file "in" theProcess1
}
I think it could be possible by using the theProcess1 output, but I don't know how to read this stream in the jar File. (The jar file doesn't know that it was started via the java file.
Any Ideas?
You can't access another java process classloader class definitions.
See this question for how to load a jar properly : How to load a jar file at runtime
Once your jar is loaded, you can use Class.forName to access the second jar desired class
EDIT :
Here is a little snippet to help you read process standard output.
//open a buffered reader on process std output
InputStreamReader ir = new InputStreamReader(theProcess1.getInputStream());
BufferedReader in = new BufferedReader(ir);
//read it line per line
String line;
while ((line = in.readLine()) != null) {
System.out.println(line);
}