Java Command Prompt Emulator - java

I'm trying to make a java program that commands through cmd.exe and prints their output. To do this, I'm using this code:
cmdLine = Runtime.getRuntime().exec("cmd.exe");
cmdLineOut = new BufferedReader(new InputStreamReader(cmdLine.getInputStream()));
cmdLineIn = new PrintWriter(cmdLine.getOutputStream());
// ...
cmdLineIn.println(command);
cmdLineIn.flush();
String s = null;
while ((s = cmdLineOut.readLine()) != null)
System.out.println(s);
Although, when input is given, the output is never printed.
EDIT: Solved
The cmdLineOut.readLine() doesn't return null when the input is empty, it freezes. Since readLine freezes at the end no other code is executed, I just put the printing of the readLine in a seperate thread.
If somebody wants to answer this better, go ahead.

You never actually execute the user's command, at least in the snippet you posted. Also, nearly all command prompt "commands" are actually just programs that are on the default program search path. You should probably just Runtime.getRuntime().exec(user_command) for each command. This means that you will have to set up the input and output streams like you have already done for each command. You are right to get input in a separate thread, since attempting to read input will block the current thread until there is actually input to read.
However, some commands, even under UNIX or Linux systems, are "built-in" (like cd), meaning that the command prompt (aka "shell") handles the commands internally. Your program will have to test the user input to see if they are calling a built-in, and specially handle calls to built-in commands. Your program should actually be portable to non-Windows computers. Of course, the user would use different commands (cp instead ofcopy), but the only part you would have to add would be handling for other OS' shells' lists of built-ins (or simply have your program implement a "cross-platform" set of built-ins - this is your shell program, you get to make the rules).

Related

jar executable from python

I have a python list of dicts that I parse to get value strings from specific keys. I need to send these strings to an executable jar that translates them then take the translation and add it back to the dict. The jar runs from the command line as:
java -jar myJar.jar -a
this opens
Enter a word to begin:
I can enter as many words as I want and it gives the translation. Then ctrl+Z+retrun to close.
I tried
cmd = ['java', '-jar', 'myJar.jar', '-a']
process = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE, universal_newlines=True)
stdout,stderr = process.communicate('word')
This works exactly once, then I have to call subprocess again. Is there a way to hold the jar open, translate a group of words and pipe the output to python? I have to do them one at a time; it's not possible to send a list or array.
'Popen.communicate' sends the input and then waits for end-of-file on output. By its documentation, it waits for the process to terminate before returning to its caller. Thus you cannot iteratively execute multiple 'communicate' calls.
You need to get the input and output streams from the process, and manage them yourself, rather than using 'communicate'. Loop, writing to the process input, and read from the process output.

Reading from keyboard and ignoring printed text

I am writing a java program (In Intellij) that accepts a command from the user and reacts to the command. The reaction is asynchronous (using a separate thread).
Scanner in = new Scanner(System.in);
String command = null;
do {
System.out.println("Enter command or q to exit: ");
command = in.nextLine();
System.out.println("Received "+command);
obj.react(command);
}while (!command.equals("q"));
The reacting object may take a while to react and prints a message after it finishes.
The problem is that if I start typing a command, and before I finish, the object prints something, the typed command is lost.
For example Here is a problematic scenario (The text in italics is the user input):
Enter command or q to exit:
go
Received go
goAgainobj finished reacting!
Received
In this case, when I Hit enter after the printed message, the received command is empty.
Is there any way to keep the typed characters even after something was printed?
If you use an actual console, printed output will not affect written input. If you type 'go' and the system prints 'Again', then the in-buffer still knows 'go'. This is unintuitive and bad to read, but it's practical to interrupt running scripts, or other programs.
This may already work on your IDE or your system, depending on OS ans IDE.
If you want something more 'pretty' then you need to fully control input and output, much like the 'top' command in linux (if you happen to know that).
You can handle this way of input better with the Console class. See: https://www.codejava.net/java-se/file-io/3-ways-for-reading-input-from-the-user-in-the-console #3
The most intuitive idea to solve your problem seems to read, and then remove all input at the time you want to print something, and reprint it, so you'd get:
> go
received go
obj finished reacting!
> go
...
You'd basically always print an input line yourself, after first reading and removing the already printed input. This is why you need the Console class, because there, input and output are synchronized, so if you print something, you know that no input will happen in the meantime.

(Blocking) interactive shell via ProcessBuilder

I built an interactive EXE which means that you can continuously send new commands to it and it will process them.
An automation of this can be implemented in Java according to this answer. However, when sending the command, the code will not wait till the command has finished. Instead, it will return the control back to the caller right away which might lead to race conditions: If the sent command was supposed to write a file, maybe the file isn't created yet before it is accessed. How can a command be sent, the output read and as soon as some input command is expected again, the sendCommand() call returns?
public synchronized void sendCommand(String command) throws IOException
{
byte[] commandBytes = (command + "\n").getBytes(UTF_8.name());
outputStream.write(commandBytes);
outputStream.flush();
}
Preferably also returning the process output in the meantime. This would be the default behavior of a non-interactive shell command which terminates once finished executing. read() blocks indefinitely until the process terminates and I do not want to hardcode the length of the expected process output or similar hacks to circumvent this shortcoming.
I decided to rewrite my binary to be non-interactive again. It turns out the expected performance gain was negligible so there was no more reason to keep it interactive and go through an increased implementation hassle.

UNIX STDOUT end symbol

I want to execute multiple commands from Java Process but I don't want to spawn a new process for executing every command. So I made an Object called Shell that holds InputStream and OutputStream for Process.
The problem is that if I don't terminate a process by appending
"exit\n"
I can't tell where is the end of the InputStream and the InputStream gets into waiting state when I've read the whole output so I need to know when to stop doing next read.
Is there some kind of a standard symbol at the end of the output?
Because what I came up with is
final String outputTerminationSignal = checksum(command);
command += ";echo \"" + outputTerminationSignal + "\";echo $?\n"
This way when I get the outputTerminationSignal line I can get the exit code and stop reading.
final String line = bufferedReader.readLine();
if (line != null && line.equals(outputTerminationSignal)) {
final String exitCode = bufferedReader.readLine();
}
Of course this is exploitable and error-prone because the real output in some case may match my generated outputTerminationSignal and the app will stop reading when it shouldn't.
I wonder if there is some standard so called "outputTerminationSignal" comming from the output I am not aware of.
Unix doesn't use a special character or symbol to indicate the end of a stream. In java, if you try to read from a stream that's at end-of-file, then you'll get an EOFException.
Having said that, if you're reading from a stream connected to a running program, then you won't get an EOFException just because the other program is idle. You would only get an EOFException if the other program has exited, or if it explicitly closes its output stream (that you are reading from). The situation you describe sounds like the shell is just idle waiting for another command. You won't get an EOF indication from the stream in this case.
You could try getting the shell to print a command prompt when it's waiting for a command, then look for the command prompt as an "end of command" indicator. Shells normally print command prompts only when they're interactive, but you might be able to find a way around that.
If you want to make the shell process exit without sending it the "exit" command, you could try closing the stream that you're using to write to the shell process. The shell should see that as an end-of-file and exit.
You could ask the shell for the PID of the spawned child, and monitor its state

Is there a way to sometimes require data from stdin and sometimes not in Java?

I am using the code below to read a sql statement from stdin on the command line:
BufferedReader in = null;
StringBuilder sb = new StringBuilder();
String line = null;
try {
in = new BufferedReader(new InputStreamReader(System.in));
while((line = in.readLine()) != null) {
sb.append(line);
}
} finally {
if (in!=null) in.close();
}
My problem is that the application needs to run sometimes with data from stdin, and sometimes not (no piped input). If there is no input in the above code, in.readLine() blocks. Is there a way to rewrite this code so that it can still run if nothing is piped in?
UPDATE: The application is designed to expect piped data from the command line, not from the keyboard.
I don't think there is any way to check if you will eventually get another line of input. Note that your current code does terminate if the user closes the input stream (e.g., with ^D in a terminal).
BufferedReader.ready() checks if there is some data on the stream. Like T.J. mentioned, you might be unlucky and ask for data right before you actually receive it, and your user will be sad because you didn't answer their query.
Scanner.hasNextLine() is a blocking operation, so probably not what you're looking for.
You could have the user specify whether or not to read from System.in, for instance by using command line arguments.
You can use ready to test whether the stream has data ready. If ready returns false, the stream didn't have data ready when you called it (it might have received data a microsecond later). If you call ready and it returns true, you know you can call read without blocking. (You may not be able to call readLine without blocking, of course.)
Unix utilities that support optionally reading from stdin usually figure out what to do based on their command line. For example, cat will read from stdin if no files are named on the command line. You could do something along those lines--add a command-line flag or option or something to indicate whether the program should try to read anything from stdin.
Another approach is to redirect input from /dev/null if there is no input that you want the program to read. In this case, you could read from stdin and get an immediate end-of-file indication. The windows equivalent is to redirect from NUL.
If you really need your program to detect whether it can read from stdin without blocking, look at InputStream.available(). But if you want to support someone typing in the program's input (or copy-pasting it into a terminal window, say) that the InputStream won't show input as available until the user actually types something.
On unix you can check whether /proc/self/fd/0 points to a file, a pipe or from the console.
$ ls -l /proc/self/fd/0
lrwx------ 1 peter peter 64 Apr 25 18:12 /proc/self/fd/0 -> /dev/pts/21
$ ls -l /proc/self/fd/0 < /dev/null
lr-x------ 1 peter peter 64 Apr 25 18:13 /proc/self/fd/0 -> /dev/null
$ echo Hello World | ls -l /proc/self/fd/0
lr-x------ 1 peter peter 64 Apr 25 18:13 /proc/self/fd/0 -> pipe:[139250355]
This will tell you if the input is a file, has been piped or is a terminal.
It depends on how your program is run when there is no piped input. Generally a program will have an open stdin and all you can do is set a timer, wait a certain amount of time for input, and if the timer expires without input, assume there isn't going to be any. The alternative would be to arrange for the program to be run with stdin closed, in which case you'll get an EOF when you try to read.
To close stdin in unix (including Mac OS) you'd write a bash script to launch your program:
#!/bin/bash
exec 0>&- # close stdin
java -jar yourProgram.jar # run your program
Of course, if you're launching from the bash command line anyway, you don't need a script:
prompt> java -jar yourProgram.jar 0>&-
But if your program is being run in a Java EE container, I don't know how you'd close stdin before launch and maybe you can't.

Categories

Resources