DOSBox commands through Java Program-word gets removed - java

String run="c:\\Program Files\DOSBox-0.74\dosbox.exe dosbox -c mount c c:\games";
The word c c:\games gets removed.
Please advise how do I prevent this? Should I use a literal to insert the spaces in the command?

A little bit of experimentation...
public class Test {
public static void main(String[] args) {
try {
ProcessBuilder pb = new ProcessBuilder("C:\\Program Files (x86)\\DOSBox-0.74\\DOSBox.exe", "dosbox", "-c", "mount c c:\\games");
pb.redirectError();
Process p = pb.start();
new Thread(new InputStreamConsumer(p.getInputStream())).start();
System.out.println("Have exited with " + p.waitFor());
} catch (IOException | InterruptedException exp) {
exp.printStackTrace();
}
}
public static class InputStreamConsumer implements Runnable {
private InputStream is;
public InputStreamConsumer(InputStream inputStream) {
is = inputStream;
}
#Override
public void run() {
int in = -1;
try {
while ((in = is.read()) != -1) {
System.out.print((char) in);
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
}

Related

Why does JShell have an echo in my shell demo?

I am writing a simple shell demo that highlights a problem I am having with JShell. When I pass JShell as an argument to /bin/zsh -c it works fine except for the fact that my Process echoes back whatever I send it.
Here is the code to my shell demo.
import java.io.*;
public class ShellDemo {
private String[] cmd = new String[] {"/bin/zsh", "-c", "jshell"};
private Process process;
public ShellDemo() {}
public void init() {
try {
ProcessBuilder pb = new ProcessBuilder(cmd);
process = pb.start();
read();
listen();
} catch (IOException ex) {
System.err.println(ex);
}
}
private void read() {
Thread thread = new Thread(() -> {
try (BufferedReader reader = process.inputReader()) {
char[] buf = new char[10000];
while (reader.ready() || process.isAlive()) {
int count = reader.read(buf, 0, 10000);
System.out.print(new String(buf, 0, count));
}
int exitVal = process.waitFor();
System.out.println("Process exited with value " + exitVal + "\n");
} catch (IOException | InterruptedException ex) {
System.err.println(ex);
}
});
thread.start();
}
private void listen() {
Thread thread = new Thread(() -> {
try (
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
BufferedWriter writer = process.outputWriter();
) {
while (process.isAlive()) {
String line = reader.readLine();
writer.write(line);
writer.newLine();
writer.flush();
}
} catch (IOException ex) {
System.err.println(ex);
}
});
thread.start();
}
public static void main(String[] args) {
ShellDemo demo = new ShellDemo();
demo.init();
}
}
Then I compile and run my shell demo, and you'll see the echo in the output.
% javac ShellDemo.java
% java ShellDemo
| Welcome to JShell -- Version 17.0.1
| For an introduction type: /help intro
jshell> System.out.println("hello world");
System.out.println("hello world")hello world
jshell>
See how System.out.println("hello world") gets echoed before the "hello world" message is read by the inputReader? Why does zsh or JShell echo what I send it?
Is there a way to avoid the echo? What's the best solution?

Run a shell file in java

In Java you can call a shell file like this:
public class Shell {
private static Shell rootShell = null;
private final Process proc;
private final OutputStreamWriter writer;
private Shell(String cmd) throws IOException {
this.proc = new ProcessBuilder(cmd).redirectErrorStream(true).start();
this.writer = new OutputStreamWriter(this.proc.getOutputStream(), "UTF-8");
}
public void cmd(String command) {
try {
writer.write(command+'\n');
writer.flush();
} catch (IOException e) { }
}
public void close() {
try {
if (writer != null) {
writer.close();
if(proc != null) {
proc.destroy();
}
}
} catch (IOException ignore) {}
}
public static void exec(String command) {
Shell.get().cmd(command);
}
public static Shell get() {
if (Shell.rootShell == null) {
while (Shell.rootShell == null) {
try {
Shell.rootShell = new Shell("su"); //Open with Root Privileges
} catch (IOException e) { }
}
}
return Shell.rootShell;
}
}
Shell.exec("echo " + bt.getLevel() + " > "+ flashfile);
right.
but I have a shell which giving an argument after executing it.
how can I pass that argument? I don't want user type anything to run this shell file. in another word, I want to fully automate a shell file.
If you want to automate a shell file with a Java programme, this can be done. You could even pipe a series of commands to this programme saved in a file and executing these as a batch.
You can execute commands batches of commands from like this:
java -cp experiments-1.0-SNAPSHOT.jar ConsoleReader < commands.txt
commands.txt is a file with a series of commands:
cmd /k date
cmd /k dir
netstat
ipconfig
Or you can with the same programme allow the user to execute commands on the command line.
Below you can find a sample programme which you can compile and be run in the above described manner.
What does it do?
It hooks a java.util.Scanner to the console input and consumes each line.
Then it spawns two threads which listen to the error and input streams and write out either to stderr or stdin.
Empty lines on the console are ignored
If you type "read " it will execute the commands on that file.
Source:
public class ConsoleReader {
public static void main(String[] args) throws IOException, DatatypeConfigurationException {
try(Scanner scanner = new Scanner(new BufferedInputStream(System.in), "UTF-8")) {
readFromScanner(scanner);
}
}
private static final Pattern FILE_INPUT_PAT = Pattern.compile("read\\s*([^\\s]+)");
private static void readFromScanner(Scanner scanner) {
while (scanner.hasNextLine()) {
try {
String command = scanner.nextLine();
if(command != null && !command.trim().isEmpty()) {
command = command.trim();
if("exit".equals(command)) {
break; // exit shell
}
else if(command.startsWith("read")) { // read from file whilst in the shell.
readFile(command);
}
else {
Process p = Runtime.getRuntime().exec(command);
Thread stdout = readFromStream(p.getInputStream(), System.out, "in");
Thread stderr = readFromStream(p.getErrorStream(), System.err, "err");
stdout.join(200);
stderr.join(200);
}
}
}
catch(Exception e) {
Logger.getLogger("ConsoleReader").log(Level.SEVERE, String.format("Failed to execute command %s", e));
}
}
}
private static void readFile(String command) throws FileNotFoundException {
Matcher m = FILE_INPUT_PAT.matcher(command);
if(m.matches()) {
String file = m.group(1);
File f = new File(file);
if (f.exists()) {
try (Scanner subScanner = new Scanner(f)) {
readFromScanner(subScanner);
}
}
}
else {
System.err.printf("Oops, could not find '%s'%n", command);
}
}
private static Thread readFromStream(InputStream stdin, PrintStream out, String name) throws IOException {
Thread thread = new Thread(() -> {
try (BufferedReader in = new BufferedReader(new InputStreamReader(stdin))) {
String line;
while ((line = in.readLine()) != null) {
out.println(line);
}
} catch (IOException e) {
Logger.getLogger("ConsoleReader").log(Level.SEVERE, "Failed to read from stream.", e);
}
}, name);
thread.setDaemon(true);
thread.start();
return thread;
}
}
Runtime.getRuntime().exec("src/[FILE LOCATION]");
I think this is the command you're looking for. Let me know if it works!

How to manage ProcessBuilder for multiple OS?

I would like to manage a Shell executor and i have some problems with Windows (not a surprise).
No pb to detect OS, no pb to start Process with ProcessBuilder, no pb to code a StreamGobbler.
But when i want to test it with JUnit, i have a strange behavior...
If i put "cmd.exe" and "/C" commands for Windows, my CMD script is not working. Without all is perfect.
Where is the problem ?
If tomorrow i want to start an exe, i think cmd.exe /c will be necessary completed with start and path to exe.
My Shell executor:
public static boolean execCmd(List<String> cmd, Map<String, String> env, File workingDir, GobblerListener gobblerListener) {
boolean result = false;
if (isWindows()) {
//cmd.add(0, "cmd.exe");
//cmd.add(1, "/C");
} else if (isUnixSolaris()) {
cmd.add(0, "/bin/ksh");
cmd.add(1, "-c");
} else {
logger.debug(ResourceBundle.getBundle(bundleName).getString("system.env.unknown"));
return result;
}
ProcessBuilder pb = new ProcessBuilder(cmd);
Map<String, String> envp = pb.environment();
for (Map.Entry<String, String> entry : env.entrySet()) {
envp.put(entry.getKey(), entry.getValue());
}
if (workingDir != null) {
pb.directory(workingDir);
}
pb.redirectErrorStream(true);
Process p = null;
try {
p = pb.start();
StreamGobbler outputGobbler = new StreamGobbler(p.getInputStream(),
gobblerListener);
outputGobbler.start();
p.waitFor();
outputGobbler.join();
int exitValue = p.exitValue();
result = (exitValue == 0 ? true : false);
} catch (InterruptedException ex) {
logger.error(ResourceBundle.getBundle(bundleName).getString(
"system.env.exec.interrupted"));
} catch (IOException e) {
logger.error(
ResourceBundle.getBundle(bundleName).getString(
"system.env.exec.exception"), e);
} finally {
if (p != null) {
p.destroy();
}
}
return result;
}
Here my StreamGobbler:
public class StreamGobbler extends Thread {
private static final Logger logger = LoggerFactory.getLogger(GobblerListener.class);
public interface Listener {
public void onLine(String line);
}
private Listener listener = null;
private InputStream is = null;
private BufferedReader reader = null;
public StreamGobbler(InputStream is, Listener onLineListener) {
this.is = is;
this.listener = onLineListener;
}
#Override
public void run() {
// keep reading the InputStream until it ends (or an error occurs)
try {
reader = new BufferedReader(new InputStreamReader(is));
try {
String line = reader.readLine();
while (line != null) {
if (listener != null && !line.trim().isEmpty())
listener.onLine(line);
line = reader.readLine();
}
} finally {
reader.close();
}
} catch (IOException e) {
logger.error("", e);
}
}
}
Thank you.

Process variable output not printed

I want a solution for printing value of process variable p. How can we print value of p? Currently value of p is: java.lang.UNIXProcess#727896
public class shellscript{
public static void main(String[] args) {
Runtime r = Runtime.getRuntime();
Process p = null;
String cmd[] = {
"/bin/bash",
"/home/aminul/myscript"
};
try {
p = r.exec(cmd);
System.out.println("testing..." + p);
System.out.println(p);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
If you want to log the standard output and the exit code of the process, try the following:
public static void main(String[] args) throws Exception
{
final Runtime r = Runtime.getRuntime();
final String cmd[] = { "/bin/bash", "/home/aminul/myscript" };
try
{
final Process p = r.exec(cmd);
new Thread()
{
public void run()
{
BufferedReader br = null;
try
{
br = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = br.readLine();
while (line != null)
{
System.out.println(line);
line = br.readLine();
}
}
catch (final Exception e)
{
e.printStackTrace();
}
finally
{
if (br != null)
try
{
br.close();
}
catch (final IOException ioe)
{
ioe.printStackTrace();
}
}
};
}.start();
p.waitFor();//wait for process to terminate
System.out.println("Exit code: "+p.exitValue());
}
catch (Exception e)
{
e.printStackTrace();
}
}
Of course, if you want to log the ErrorStream as well, you will have to start another thread.
Process don't have name attribute. But you can use pid.
You can try it in this way
Field field=p.getClass().getField("pid"); // use reflection since pid is private
System.out.println(field);
But you can't use
System.out.println(p)
Since Process don't have a override toString() method

Running a java program from another java program

I am working on a simple java program. It simply compiles and executes another java program. I am using Runtime.exec() function to compile and run. There is no problem with compilation. but when it runs, if the second program needs an input to read from keyboard, I can't give it from the master process. I used getOutputStream() function. but it couldn't help. I will provide my code.
public class sam {
public static void main(String[] args) throws Exception {
try {
Process p = Runtime.getRuntime().exec("javac sam2.java");
Process p2 = Runtime.getRuntime().exec("java sam2");
BufferedReader in = new BufferedReader(
new InputStreamReader(p2.getInputStream()));
OutputStream out = p.getOutputStream();
String line = null;
line = in.readLine();
System.out.println(line);
input=input+"\n";
out.write(input.getBytes());
p.wait(10000);
out.flush();
}catch (IOException e) {
e.printStackTrace();
}
}
}
This is my master program(sam.java).
The following is the code of sam2.java
public class sam2 {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String str;
System.out.println("Enter the number..\n");
str = br.readLine();
System.out.println(Integer.parseInt(str));
}
}
There is no problem, if my second program has only printing statements. But the problem arises when I have to read something from the other.
It is a bit strange but you can run the second program without forking it. Just calling the main method in it. So forget the runtime section and do this:
sam2.main(new String[0]);
Of course this way you must compile sam2 at compile time
Each process needs to be allowed to run and finish. You can use Process#waitFor for this purpose. Equally, you need to consume any output from the process at the same time. waitFor will block so you will need use a Thread to read the input (and if you need to, write output to the process)
Depending on the location of the java/class file, you may also need to specify a starting folder from which the execution of the process can start.
Most of this significantly easier using ProcessBuilder
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public class CompileAndRun {
public static void main(String[] args) {
new CompileAndRun();
}
public CompileAndRun() {
try {
int result = compile("compileandrun/HelloWorld.java");
System.out.println("javac returned " + result);
result = run("compileandrun.HelloWorld");
} catch (IOException | InterruptedException ex) {
ex.printStackTrace();
}
}
public int run(String clazz) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("java", clazz);
pb.redirectError();
pb.directory(new File("src"));
Process p = pb.start();
InputStreamConsumer consumer = new InputStreamConsumer(p.getInputStream());
consumer.start();
int result = p.waitFor();
consumer.join();
System.out.println(consumer.getOutput());
return result;
}
public int compile(String file) throws IOException, InterruptedException {
ProcessBuilder pb = new ProcessBuilder("javac", file);
pb.redirectError();
pb.directory(new File("src"));
Process p = pb.start();
InputStreamConsumer consumer = new InputStreamConsumer(p.getInputStream());
consumer.start();
int result = p.waitFor();
consumer.join();
System.out.println(consumer.getOutput());
return result;
}
public class InputStreamConsumer extends Thread {
private InputStream is;
private IOException exp;
private StringBuilder output;
public InputStreamConsumer(InputStream is) {
this.is = is;
}
#Override
public void run() {
int in = -1;
output = new StringBuilder(64);
try {
while ((in = is.read()) != -1) {
output.append((char) in);
}
} catch (IOException ex) {
ex.printStackTrace();
exp = ex;
}
}
public StringBuilder getOutput() {
return output;
}
public IOException getException() {
return exp;
}
}
}
Now obviously, you should check the return results of the processes, and may be produce a better mechanism for interacting with the processes, but that's the basic idea...
You can just call the main method of the second class. The main method is just like any other static method.
This is what worked for me:
try {
single.main(new String[0]);
} catch (Exception e) {
JOptionPane.showMessageDialog(null, e);
}
Just call the main class file. For example, if your java class file name is xyz.java, you can call and execute the same in java swing application on click of a JButton, code is
private void Btn_createdatabaseActionPerformed(java.awt.event.ActionEvent evt) {
xyz.main(new String[0]);
}
That's it...

Categories