I am trying to make it so that when a user clicks a button, a new screen appears and automatically runs a command line process, and they are able to see the outputs of this process.
I thought that I might be able to use a JTextArea to set text to.
Here's what I've got at the moment:
runButton.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent r)
{
JFrame runFrame = new JFrame("Running process...");
runFrame.setVisible(true);
runFrame.setSize(500, 400);
runFrame.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
runFrame.setLayout(null);
JTextArea run = new JTextArea();
run.setBounds(100,50,300,200);
runFrame.add(run);
Runtime runtime = Runtime.getRuntime();
Process process = null;
try
{
process = runtime.exec("cat /cmd/h:/testfile");
}
catch (IOException e)
{
e.printStackTrace();
}
InputStream runStream = process.getInputStream();
InputStreamReader runStreamReader = new InputStreamReader(runStream);
BufferedReader br = new BufferedReader(runStreamReader);
String line;
StringBuilder sb = new StringBuilder();
try
{
while ((line = br.readLine()) != null)
{
sb.append(line);
}
}
catch (IOException e)
{
e.printStackTrace();
}
run.setText(sb.toString());
}
});
The error I'm getting with this is:
Cannot run program "cat": CreateProcess error=2, The system cannot find the file specified
I was trying to test opening a file to test this, which just contains lines of random letters.
EDIT:
I'm not sure I explained clearly what I need this to do.
What I want is for a command to be run in command line that opens a file. I then want the result of the command line to be output into the JTextArea.
EDIT 2:
I have tried to change my command to "ping riot.de -t". This will ping riots server every so often and it returns a response with the response time.
Upon running this, the new frame is just black, and java freezes up.
maybe the env of your java application execution has not the right path of cat cmd? you have try to specify absolute path for cat command?
Related
I would like to run a hidden script file that resides in the current location using process builder. with the following code
// System.out.println("line"+reader.readLine());
ProcessBuilder builder = new ProcessBuilder(shfile.getAbsolutePath());
builder.redirectErrorStream(true);
Process process = builder.start();
BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()));
String output = null;
System.out.println("out"); //===printing this
while (null != (output = br.readLine()))
{
System.out.println("in"); //not printing this
System.out.println(">>"+output);
}
int rs = process.waitFor();
but it hangs in the br.readline()..
but when I run the same script file using the following command in terminal
sh .script.sh
it executes and gives me the expected results
I looked into all the loops in the forum everyone asks to handle input stream and error stream in threads or do a redirect error stream. I have added a redirect error stream but still it hangs.
when i press ctrl+c it prints the initial lines of the output and exits.
Content of my script file
#!/bin/sh
cd /home/ats/cloudripper/lke_factory_asb_v2/lk_assets_factory_release/
sh ./LKE_run_Diablo.sh 0a0e0c3dc893
So how to handle this situation.
Process builder have special API to redirect child process input, output and error streams. See documentation
If you need both child and parent process to use same console you should use INHERIT mode redirection. An example:
public class ChildProcessOutputProxy {
public static void main(String[] args) {
ProcessBuilder builder = new ProcessBuilder("whoami");
builder.redirectOutput(Redirect.INHERIT);
builder.redirectErrorStream(true);
try {
var child = builder.start();
child.waitFor();
} catch (IOException e) {
System.err.println(e.getMessage());
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
I've been trying to make an app to act as a ssh / scp client to make transferring files easier from my laptop to my desktop and currently I have been able to get the output of a ls command and get the file tree for the host and remote user, however this requires input in the terminal I am running the app with.
Is it possible to be able to embed a terminal window into a gui as I have went about making an interpreter however things like tab completion and running, for example, python3 don't work. I am also hoping to have full use of a terminal and be able to run commands like vim rather than just print the output of commands which is what I currently have.
My code for executing the commands is:
public void processCmd(String command) {
if (command.equals("exit")) {
System.exit(0);
} else if (command != null && !command.isEmpty()) {
execCommand(command);
}
}
public void execCommand(String input) {
String result = null;
try {
Runtime r = Runtime.getRuntime();
Process p = r.exec(input);
BufferedReader in =
new BufferedReader(new InputStreamReader(p.getInputStream()));
String inputLine;
while ((inputLine = in.readLine()) != null) {
System.out.println(inputLine);
result += inputLine;
}
in.close();
} catch (IOException e) {
System.out.println("Error");
}
}
The main problem is that when anything like python or vim is run, the app will hang and not do anything, python won't even show up in terminal, however, if I run vim, it will change the terminal screen (not in the app) to mostly vim but without the bottom bar.
I'm having trouble with ProcessBuilder not running a command on the server.
Early in my project I use Runtime.exec() just to retrieve output from a program which works fine:
private List<SatelliteCode> getSatelliteCodes() {
List<SatelliteCode> codes = new ArrayList<>();
Runtime runtime = Runtime.getRuntime();
String[] commands = { "w_scan", "-s?" };
Process process;
try {
process = runtime.exec(commands);
BufferedReader error = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s = error.readLine(); // discard first line
while ((s = error.readLine()) != null) {
s = s.trim();
int i = s.indexOf('\t'); // separated by a tab!?!?
codes.add(new SatelliteCode(s.substring(0, i), s.substring(i)));
}
} catch (IOException e) {
e.printStackTrace();
}
return codes;
}
Running this in the terminal works fine and I get all the output I need:
w_scan -fs -cGB -sS19E2 > channels.conf
However, the server needs to grab the ongoing output from the 'process.getErrorStream()' to display in the web interface. What is actually happening is the ProcessBuilder is failing and returning an exit code of 1.
The function that initialises the ProcessBuilder and to start the scan running is [EDIT 1]:
private static StringBuilder scan_error_output = null;
#Override
public boolean startSatelliteScan(String user, String country_code, String satellite_code) {
UserAccountPermissions perm = validateUserEdit(user);
if (perm == null) return false;
Shared.writeUserLog(user, Shared.getTimeStamp() +
": DVB satellite scan started " +
country_code + " - " + satellite_code +
System.lineSeparator() + System.lineSeparator());
scan_error_output = new StringBuilder();
new ScanThread(country_code, satellite_code).start();
// write out country code and satellite code to prefs file
BufferedWriter bw = null;
try {
bw = new BufferedWriter(new FileWriter(satellite_last_scan_codes));
bw.write(country_code); bw.newLine();
bw.write(satellite_code); bw.newLine();
bw.close();
} catch (IOException e) {
e.printStackTrace();
}
return true;
}
That will then run two other threads on the server, one that will run the scan itself and wait for it to finish so that it can get the final scan data. And the other which constantly updates the output from the std error stream which is then polled at intervals from the clients browser. This is much like showing the ongoing output from the terminal.
The scan thread (which fails to start the process) [EDIT 1]:
private static class ScanThread extends Thread {
private String cc, sc;
public ScanThread(String country_code, String satellite_code) {
cc = country_code;
sc = satellite_code;
}
public void run() {
ProcessBuilder pb = new ProcessBuilder("/usr/bin/w_scan",
"-fs", "-c" + cc, "-s" + sc);
pb.redirectOutput(new File(satellite_scan_file));
Process process;
try {
System.out.println("Scan thread started");
process = pb.start();
IOScanErrorOutputHandler error_output_handler = new IOScanErrorOutputHandler(process.getErrorStream());
error_output_handler.start();
int result = process.waitFor();
System.out.println(cc + " - " + sc + " - " +
"Process.waitFor() result " + result);
} catch (IOException e) {
System.out.println(e.getMessage());
e.printStackTrace();
} catch (InterruptedException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
System.out.println("Scan thread finished");
}
}
The error output stream thread which captures the output which obviously doesn't start due to the scan thread failing:
private static class IOScanErrorOutputHandler extends Thread {
private InputStream inputStream;
IOScanErrorOutputHandler(InputStream inputStream) {
this.inputStream = inputStream;
}
public void run() {
Scanner br = null;
try {
System.out.println("Scan thread Error IO capture running");
br = new Scanner(new InputStreamReader(inputStream));
String line = null;
while (br.hasNextLine()) {
line = br.nextLine();
scan_error_output.append(line + System.getProperty("line.separator"));
}
} finally {
br.close();
}
System.out.println("Scan thread Error IO capture finished");
scan_error_output = null;
}
}
And the server function which returns the std error output progress:
#Override
public String pollScanResult(String user) {
if (validateUserEdit(user) == null) return null;
StringBuilder sb = scan_error_output; // grab instance
if (sb == null) return null;
return sb.toString();
}
As mentioned above, Runtime.exec() works fine, but the ProcessBuilder is failing.
NB: I'm on Linux Mint 18.1, using Apache Tomcat 8 as the server, linux default JDK 8 and GWT 2.7 [Correction from 2.8] in Eclipse Neon.
Can anyone see what I am doing wrong?
Many thanks in advance...
[EDIT 1]
Whilst developing this on another machine, Linux Mint 17.2, JDK 8 and Apache Tomcat 7, for DVB-T, this method worked fine and polling for the scan output showed up in the client's browser.
The ProcessBuilder.start still returns 1 and an empty file is created for the output scan file.
[EDIT 2]
It appears that the reason the ProcessBuilder is failing is because the user 'tomcat8' doesn't have permissions to run 'w_scan'. 'w_scan' works from the terminal, but not from the tomcat server. Somehow I've got to fix that now.
[SOLUTIONS]
After being put in the right direction by VGR for getting the error stream from the ProcessBuilder, I started digging further and found I was getting:
main:3909: FATAL: failed to open '/dev/dvb/adapter0/frontend0': 13 Permission denied
Apache tomcat 8 didn't have permission to access the DVB-S frontend to run a scan. This was fixed in two ways:
1 - 03catalina.policy I added the extra permissions (whether they made a difference I do not know).
grant codeBase "file:/dev/dvb/-" {
permission java.io.FilePermission "file:/dev/dvb/-", "read, write";
permission java.security.AllPermission;
};
2 - The dvb frontends belong to the 'video' group. So I needed to add the user tomcat8 to that group.
usermod -a -G video tomcat8
All works for now...
You are not doing the same thing with ProcessBuilder that you’re doing with Runtime.exec, so I don't know why you think ProcessBuilder is the problem.
You have a few problems with how you’re writing the command’s output to a file.
First, the presence of ">", satellite_scan_temp_file in your ProcessBuilder command is incorrect. Output redirection is not part of any command; it is handled by a shell. But when you run with Runtime.exec or ProcessBuilder, you are not running in a shell, you are executing the process directly. Neither w_scan nor any other command considers > a special character.
The correct way to redirect to a file is with the redirectOutput method:
ProcessBuilder pb = new ProcessBuilder(
"/usr/bin/w_scan", "-fs", "-s" + satellite_code, "-c" + country_code);
pb.redirectOutput(new File(satellite_scan_temp_file));
Second, your ScanThread code is ignoring the (currently incorrect) redirect, and is attempting to read the command’s output. But there is no output, because you are redirecting it all to a file.
Once you are properly redirecting output to a file, you can remove your BufferedReader and BufferedWriter loops completely.
Finally, it is worth noting that the error output you captured probably told you that > is not a valid argument to the w_scan process.
File wd = new File("/bin");
Process proc = null;
try {
proc = Runtime.getRuntime().exec("/bin/bash", null, wd);
} catch (IOException e) {
logger.info(e);
e.printStackTrace();
}
if (proc != null) {
BufferedReader in = new BufferedReader(new InputStreamReader(proc.getInputStream()));
PrintWriter out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(proc.getOutputStream())), true);
//out.println("su - root");
out.println("cp /usr/rock/Masterfile.xls /usr/rock/generatedfile/");
out.println("mv /usr/rock/generatedfile/Masterfile.xls /usr/rock/generatedfile/userid.xls");
try {
String line;
while ((line = in.readLine()) != null) {
logger.info(line);
}
proc.waitFor();
in.close();
out.close();
proc.destroy();
} catch (Exception e) {
logger.info(e);
e.printStackTrace();
}
}
I am trying to copy master file and want to rename according to the userid. Code does not showing any error but i dont see any file in the folder i specify. I tried with sudo root command even its not copying and renaming the file. How should i do in order to run copy and rename command to run successfully from java program.
You're not reading from the process's standard error. So if your cp and mv commands are reporting errors, you won't be seeing them.
It's possible to read from the process's standard error, but that's complicated if you're using Runtime.getRuntime().exec() because reading from standard error needs to be done in a separate thread to reading from standard output.
Java 5 introduced a new class for running external processes: ProcessBuilder. In my opinion, the single biggest advantage of a ProcessBuilder is that you can redirect the standard error of the process into its standard output. That leaves you with only one stream to read from, and hence no need for a separate thread.
I would recommend replacing your use of Runtime.getRuntime().exec(...) with the following:
ProcessBuilder builder = new ProcessBuilder("/bin/bash");
builder.directory(wd);
builder.redirectErrorStream(true);
proc = builder.start();
If the files aren't being copied, then chances are that cp and mv are reporting errors. Making this change should hopefully allow you to see the errors being reported.
I have a program that takes in a file as an input and produces an xml file as an output. When I call this from the command line it works perfectly. I try calling it from a Java program with the following code.
try
{
Process proc = Runtime.getRuntime().exec(c);
try
{
proc.waitFor();
}
catch(InterruptedException e)
{
System.out.println("Command failed");
}
}
catch(IOException e)
{
System.out.println("Command failed");
e.printStackTrace();
}
The program seems to be running fine, as it creates an xml file; however, the xml file is empty when I open it. I'm not encountering any exceptions in my Java program, so I'm baffled as to what the problem could be. Why would the command line program work fine normally, but then when called from Java not output anything to the file it created. I was thinking maybe it was some sort of permissions thing. I tried running the program as sudo (I'm using Linux) but to no avail. This problem doesn't seem to be anything I could find an answer to online. Hopefully somebody on here might be able to tell what's going on. :)
Get the output and error streams from your process and read them to see what is happening. That should tell you what's wrong with your command.
For example:
try {
final Process proc = Runtime.getRuntime().exec("dir");
try {
proc.waitFor();
} catch (final InterruptedException e) {
e.printStackTrace();
}
final BufferedReader outputReader = new BufferedReader(new InputStreamReader(proc
.getInputStream()));
final BufferedReader errorReader = new BufferedReader(new InputStreamReader(proc
.getErrorStream()));
String line;
while ((line = outputReader.readLine()) != null) {
System.out.println(line);
}
while ((line = errorReader.readLine()) != null) {
System.err.println(line);
}
} catch (final IOException e) {
e.printStackTrace();
}
If there is no output in either stream, then I would next examine the external program and the command being sent to execute it.
Did you try launching the process from outside java?
For me, I wrote a jar file that output a file and ran that from the command line in another java program. It turns out that there was a fundamental check in my jar file that I had forgotten about on the number of characters in an input string (my bad). If the count of the characters was smaller than 8 there was no output file. If the number of characters was greater than 8, the output file came out without any trouble using the following code:
String cmdStr = "java -jar somejar.jar /home/username/outputdir 000000001";
try
{
Runtime.getRuntime().exec(cmdStr);
Runtime.getRuntime().runFinalization();
Runtime.getRuntime().freeMemory();
log.info("Done");
}
catch (IOException e)
{
log.error(System.err);
}
Not sure if I really need everything here but, hey, it works. Note: no waitFor seems to be necessary in my case.
process input (actually output of the process!) and error streams has to be handled before waiting for the process termination.
This should work better
try
{
Process proc = Runtime.getRuntime().exec("anycomand");
BufferedReader outSt = new BufferedReader(new InputStreamReader(proc.getInputStream()));
BufferedReader errSt = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
String line;
while ((line = outSt.readLine()) != null)
{
System.out.println(line);
}
while ((line = errSt.readLine()) != null)
{
System.err.println(line);
}
proc.waitFor();
}
catch (final IOException e)
{
e.printStackTrace();
}
but to understand better how Runtime exec works it is worth reading
the classic article
When Runtime.exec() won't
which provide useful sample code (better than the one above!)