I wanted to run a script from java class.
I was able to do it with ProcessBuilder.
Now I am struggling to pass data as an argument to the script. I can pass a string, but I am having trouble passing list of data (data read from a CSV file).
One that I tried was using StringBuffer and passing the data as Bytes
StringBuffer sb = new StringBuffer();
ArrayList argsList = new ArrayList();
// append the sb from record.
//convert it to bytes
//sb.toString() contains my data with a delimiter ';'
// sb.toString().getBytes("UTF-8").toString()
argsList.add(0,"Continuum/anaconda3/envs/sth/python");
argsList.add(1,"python/test.py");
argsList.add(2,"python/test.py");
argsList.add(3,sb.toString().getBytes("UTF-8").toString())
ProcessBuilder builder = new ProcessBuilder(argsList);
Process p = builder.start();
I can not pass sb.toString().getBytes("UTF-8") to the process builder.
I get java.lang.ArrayStoreException
On the other hand, if I pass sb.toString(), I get
java.io.IOException: Cannot run program Continuum/anaconda3/envs/sth/python, CreateProcess error=206, The filename or extension is too long
add it to list of commands to process builder.
How can I read what I passed in python?
Is this even the right way to pass data ( row X column)?
Thanks
You can try below code ::
import java.io.*;
class RunPythonCommand {
public static void main(String [] args) {
try {
String prg = "import sys\nprint int(sys.argv[1])+int(sys.argv[2])\n";
BufferedWriter out = new BufferedWriter(new FileWriter("sample_code.py"));
out.write(prg);
out.close();
int param1 = 10;
int param2 = 32;
ProcessBuilder pb = new ProcessBuilder("python", "sample_code.py", "" + param2, "" + param1);
Process p = pb.start();
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
int ret = new Integer(in.readLine()).intValue();
System.out.println("value is : " + ret);
} catch (Exception e) {
System.out.println(e);
}
}
}
Hope it will help you
You can pass args as array.:
final String PYTHON = "python";
final String SCRIPT_PATH = new File("Pyscript.py").getPath();
final String ACTION = "-aexport";
final String[] CMD_ARRAY = {PYTHON, SCRIPT_PATH, ACTION};
ProcessBuilder processBuilder = new ProcessBuilder(CMD_ARRAY);
Related
There is such code, I pass two parameters to the input and get the result of this method in the console, I need to save the result in a variable and pass it to another method how to do it right? Please do not rush tomatoes with a beginner in programming, I will be glad to any help. The result of the screen method.
enter image description here
public static String activation(String serialNumber, String keyName) throws IOException, InterruptedException, SQLException {
LocalDate futureDate = LocalDate.now().plusMonths(12);
String formattedDate = futureDate.format(DateTimeFormatter.ofPattern("yyyyMMdd"));
String[] command =
{
"cmd",
};
Process p = Runtime.getRuntime().exec(command);
//new Thread(new SyncPipe(p.getErrorStream(), System.err)).start();
new Thread(new SyncPipe(p.getInputStream(), System.out)).start();
PrintWriter stdin = new PrintWriter(p.getOutputStream());
stdin.println("C:\\tdes_ecb.exe " + serialNumber + " " + keyName + " " + formattedDate);
stdin.close();
int returnCode = p.waitFor();
String code = Integer.toString(returnCode);
return code;
}
static class SyncPipe implements Runnable {
public SyncPipe(InputStream istrm, OutputStream ostrm) {
inputStream = istrm;
outputStream = ostrm;
}
public void run() {
try {
final byte[] buffer = new byte[1024];
for (int length = 0; (length = inputStream.read(buffer)) != -1; ) {
outputStream.write(buffer, 0, length);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < buffer.length; i++) {
char c = (char) buffer[i];
sb.append(c);
}
String convertedString = sb.toString();
key(convertedString);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private final OutputStream outputStream;
private final InputStream inputStream;
}
public void SyncPipe(InputStream inputStream, OutputStream outputStream) {
this.inputStream = inputStream;
this.outputStream = outputStream;
}
For you to get the result of Runtime.getRuntime().exec(command) into a variable, there is no need for a separate thread, you can simple read it right from your object Process and store in a String or StringBuilder, after this it is a matter of understanding the text and splitting it based on your rules.
To immediately read the result of a process:
final StringBuilder ret = new StringBuilder();
final Runtime rt = Runtime.getRuntime();
final String[] commands = { "cmd", "/c", "cd c:\\myuser" };
final Process proc = rt.exec(commands);
final BufferedReader stdInput = new BufferedReader(new InputStreamReader(proc.getInputStream()));
final BufferedReader stdError = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String s = null;
while ((s = stdInput.readLine()) != null) {
ret.append(s).append("\n");
}
while ((s = stdError.readLine()) != null) {
ret.append(s).append("<br />");
}
String res = ret.toString();
After the code above you‘ll have all the text from the results in a String, now it is a matter of splitting it and/or removing unnecessary information. For this you can use the methods indexOf, split and removeAll combined, they are all methods inside the String class.
In you case, to make it simple we can divide the splitting in 3 stages.
1) Ignore the first empty line (\r\n)
2) Ignore the whole first line (command and arguments)
3) Use only the text starting from the position 0 until the next line break
String res = "\r\nC:\\User\\aaa\\bbb\\ccc\\tdex_ecb.exe 000000 111111 33333 44444 \r\n INFO I WANT\r\n C:\\\\User\\\\aaa\\\\bbb\\\\ccc\\\\";
res = res.substring(2);
res = res.substring(res.indexOf("\r\n")+2);
res = res.substring(0, res.indexOf("\r\n"));
System.out.println(res);
Now your variable res has only the text you want to pass to another method.
I am not clear of some parts of your requirement. If it is to get the output of the child process as input in the main Java process, then I don't think it is feasible directly through the Java APIs.
Indirect way of getting child process output in the main Java process
I am not sure if you tried this, but you can redirect the output of the child process into a file and read from that file once the process is over, within the same process. (Of course, if your output data in sensitive, you may not want to do this.)
String filePath = "C:/Temp/abc.txt";
/* Create the process and redirect its output to a new file. */
ProcessBuilder pb = new ProcessBuilder().command( "C:\\Temp\\echo.bat" ) //Replace this with your command
.redirectOutput( Redirect.to( new File( filePath ) ) );
Process p = pb.start();
p.waitFor(); //Now, wait for the process to get over...
/* Now, read from the generated file. */
List<String> lines = Files.readAllLines( Paths.get( filePath ) );
Linking the outputs and inputs, resp., of child and main process
However, if your need is to simply display the output of the child process in the console of the main Java process, you may do this.
Process p = new ProcessBuilder().command( "C:\\Temp\\echo.bat" ) //Replace this with your command
.inheritIO().start();
p.waitFor();
My Java program needs to launch agrep.exe with parameters for all pairs of elements in a big matrix and get number of matching errors of two stings. I've wrote a code, but it runs very slowly. Can I speed up this part of code? Or, maybe, you can suggest me some java implementation of agrep function?
public static double getSignatureDistance(String one, String two) throws IOException, InterruptedException {
String strReprOne = one.replace(".*","").replace("\\.",".");
String strReprTwo = two.replace(".*","").replace("\\.",".");
PrintWriter writer = new PrintWriter("tmp.txt", "UTF-8");
writer.print(strReprTwo);
writer.close();
List<String> cmd = new ArrayList<>();
cmd.add("agrep.exe");
cmd.add("-B");
cmd.add(one);
cmd.add("tmp.txt");
ProcessBuilder pb = new ProcessBuilder(cmd);
pb.redirectErrorStream(true);
Process proc = pb.start();
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
StringBuilder lineBuilder = new StringBuilder();
String line = "";
char[] buf = new char[2];
while (in.read(buf) == 2) {
lineBuilder.append(buf);
}
line = lineBuilder.toString();
Pattern p = Pattern.compile("(\\d+)\\serror");
Matcher m = p.matcher(line);
double agrep = 0;
if(m.find()) {
agrep = Double.valueOf(m.group(1));
}
in.close();
proc.destroy();
double length = strReprOne.length();
return agrep/length;
}
Can I use FREJ library for this purpose? For example, perform match of strings, get match result and multiply it by length of matched region?
Nobody knows, so I've used FREJ library.
I am trying to run a sed command from java without success. Here is my java code:
String[] cmd = {"sed", "-i", "'"+lineIndex+"s/"+line+"/"+currentBid+"/g'", "/data/jsp/items.xml"};
Runtime.getRuntime().exec(cmd);
I also tried:
String[] cmd = {"/bin/sh","-c","sed", "-i", "'"+lineIndex+"s/"+line+"/"+currentBid+"/g'", "/data/jsp/items.xml"};
Runtime.getRuntime().exec(cmd);
Thing is, if I print out the contents of the cmd String and run it in a terminal it does work. It's just not executing it from java for some reason. Te make this more clear, when I run the command directly from a terminal the file "items.xml" changes. When I run it from java the file does not change. I've verified that the command is correct as sown below.
Am I missing something?
The output from cmd is sed -i '21s/2/102/g' /data/jsp/items.xml
** EDIT
I made the following changes based on comments below. No change in output however.
String[] cmd = {"/bin/sh","-c","sed", "-i", "'"+lineIndex+"s/"+line+"/"+currentBid+"/g'", "/data/jsp/items.xml"};
Process p = Runtime.getRuntime().exec(cmd);
p.waitFor();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line2 = reader.readLine();
while (line2 != null) {
line2 = reader.readLine();
}
reader.close();
Try that :)
The advantage of this solution , it's more easier to debugging because you have the temporary file !
String lineIndex="21";
String line="2";
String currentBid="102";
File temp = File.createTempFile("temp-sh", ".sh");
FileWriter fw = new FileWriter(temp);
fw.write("#!/bin/bash\n");
fw.write("sed -i '"+lineIndex+"s/"+line+"/"+currentBid+"/g' data/jsp/items.xml\n");
fw.close();
System.out.println(". "+temp.getAbsolutePath());
Runtime.getRuntime().exec(". "+temp.getAbsolutePath());
You should probably use a ProcessBuilder instead of Runtime.exec, perhaps something like this -
try {
String replaceCommand ="'"+lineIndex+"s/"+line+"/"+currentBid+"/g'";
String [] cmd = new String[] {
"sed", "-i", replaceCommand, "/data/jsp/items.xml"
};
Process process = new ProcessBuilder(cmd)
.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String lineRead;
System.out.printf("Output of running %s is:",
Arrays.toString(cmd));
while ((lineRead = br.readLine()) != null) {
System.out.println(lineRead);
}
} catch (IOException e) {
e.printStackTrace();
}
You need to make sure the path to the file is correct, java may not have the same path to the file unless it is in the jar. You can do this by trying to open the file or checking if it exists before passing it to the command.
see: How to read file from relative path in Java project? java.io.File cannot find the path specified
Honestly there is no need to externally execute sed in this case. Read the file in Java and use Pattern. Then you have code that could run on any platform. Combine this with org.apache.commons.io.FileUtils and you can do it in a few lines of code.
final File = new File("/data/jsp/items.xml");
String contents = FileUtils.readFileToString(file, StandardCharsets.UTF_8.name());
contents = Pattern.compile(line).matcher(contents).replaceAll(currentBid);
FileUtils.write(file, contents);
Or, in a short, self-contained, correct example
import org.apache.commons.io.FileUtils;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.regex.Pattern;
public final class SedUtil {
public static void main(String... args) throws Exception {
final File file = new File("items.xml");
final String line = "<bid>\\d+</bid>";
final String currentBid = "<bid>20</bid>";
final String data = "<bids><bid>10</bid></bids>";
FileUtils.write(file, data);
sed(file, Pattern.compile(line), currentBid);
System.out.println(data);
System.out.println(FileUtils.readFileToString(file, StandardCharsets.UTF_8));
}
public static void sed(File file, Pattern regex, String value) throws IOException {
String contents = FileUtils.readFileToString(file, StandardCharsets.UTF_8.name());
contents = regex.matcher(contents).replaceAll(value);
FileUtils.write(file, contents);
}
}
which gives output
<bids><bid>10</bid></bids>
<bids><bid>20</bid></bids>
I am now on a linux machine. I have a Java program which would run some linux command, for example ps, top, list or free -m.
The way to run a command in Java is as follows:
Process p = Runtime.getRuntime().exec("free -m");
How could I collect the output by Java program? I need to process the data in the output.
Use Process.getInputStream() to get an InputStream that represents the stdout of the newly created process.
Note that starting/running external processes from Java can be very tricky and has quite a few pitfalls.
They are described in this excellent article, which also describes ways around them.
To collect the output you could do something like
Process p = Runtime.getRuntime().exec("my terminal command");
p.waitFor();
BufferedReader buf = new BufferedReader(new InputStreamReader(
p.getInputStream()));
String line = "";
String output = "";
while ((line = buf.readLine()) != null) {
output += line + "\n";
}
System.out.println(output);
This would run your script and then collect the output from the script into a variable. The link in Joachim Sauer's answer has additional examples of doing this.
As for some command need to wait for a while, add p.waitFor(); if necessary.
public static void main(String[] args) {
CommandLineHelper obj = new CommandLineHelper();
String domainName = "google.com";
//in mac oxs
String command = "ping -c 3 " + domainName;
String output = obj.executeCommand(command);
System.out.println(output);
}
private 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");
}
} catch (Exception e) {
e.printStackTrace();
}
return output.toString();
}
The technicalities of calling an external process are quite involved. The jproc library helps abstracting over these by automatically consuming the output of the command and providing the result as a string. The example above would be written like this:
String result = ProcBuilder.run("free", "-m");
It also allows to set a timeout, so that your application isn't blocked by an external command that is not terminating.
public String RunLinuxGrepCommand(String command) {
String line = null;
String strstatus = "";
try {
String[] cmd = { "/bin/sh", "-c", command };
Process p = Runtime.getRuntime().exec(cmd);
BufferedReader in = new BufferedReader(new InputStreamReader(p.getInputStream()));
while ((line = in.readLine()) != null) {
strstatus = line;
}
in.close();
} catch (Exception e) {
StringWriter sw = new StringWriter();
PrintWriter pw = new PrintWriter(sw);
e.printStackTrace(pw);
pw.flush();
String stackTrace = sw.toString();
int lenoferrorstr = stackTrace.length();
if (lenoferrorstr > 500) {
strstatus = "Error:" + stackTrace.substring(0, 500);
} else {
strstatus = "Error:" + stackTrace.substring(0, lenoferrorstr - 1);
}
}
return strstatus;
}
This functioin will give result of any linux command
I want to invoke outlook from the command line (for various reasons) and wanted to know how I go about discovering the Path to the Outlook.exe file.
I'm pretty sure it's stored in the registry, but was wondering how to go about reading that from Java.
thanks
I found a Microsoft page that describes the procedure, just not in Java.
So I guess the question becomes how do I access the registry from java.
I found this site that might be able to help you. It's a Java Registry wrapper, seems to have a lot of features but no idea how robust the implementation is.
Using Otis' answer the following code does it nicely.
static String getOutlookPath() {
// Message message = new Message();
final String classID;
final String outlookPath;
{ // Fetch the Outlook Class ID
int[] ret = RegUtil.RegOpenKey(RegUtil.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\Outlook.Application\\CLSID", RegUtil.KEY_QUERY_VALUE);
int handle = ret[RegUtil.NATIVE_HANDLE];
byte[] outlookClassID = RegUtil.RegQueryValueEx(handle, "");
classID = new String(outlookClassID).trim(); // zero terminated bytes
RegUtil.RegCloseKey(handle);
}
{ // Using the class ID from above pull up the path
int[] ret = RegUtil.RegOpenKey(RegUtil.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\CLSID\\" + classID + "\\LocalServer32", RegUtil.KEY_QUERY_VALUE);
int handle = ret[RegUtil.NATIVE_HANDLE];
byte[] pathBytes = RegUtil.RegQueryValueEx(handle, "");
outlookPath = new String(pathBytes).trim(); // zero terminated bytes
RegUtil.RegCloseKey(handle);
}
return outlookPath;
}
Below is a solution modified slightly from a similar problem: https://stackoverflow.com/a/6194710/854664
Notice I'm using .pst instead of .xls
import java.io.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ShowOutlookInstalled {
public static void main(String argv[]) {
try {
Process p = Runtime.getRuntime()
.exec(new String[] { "cmd.exe", "/c", "assoc", ".pst" });
BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String extensionType = input.readLine();
input.close();
// extract type
if (extensionType == null) {
outlookNotFoundMessage("File type PST not associated with Outlook.");
} else {
String fileType[] = extensionType.split("=");
p = Runtime.getRuntime().exec(
new String[] { "cmd.exe", "/c", "ftype", fileType[1] });
input = new BufferedReader(new InputStreamReader(p.getInputStream()));
String fileAssociation = input.readLine();
// extract path
Pattern pattern = Pattern.compile("\".*?\"");
Matcher m = pattern.matcher(fileAssociation);
if (m.find()) {
String outlookPath = m.group(0);
System.out.println("Outlook path: " + outlookPath);
} else {
outlookNotFoundMessage("Error parsing PST file association");
}
}
} catch (Exception err) {
err.printStackTrace();
outlookNotFoundMessage(err.getMessage());
}
}
private static void outlookNotFoundMessage(String errorMessage) {
System.out.println("Could not find Outlook: \n" + errorMessage);
}
}