This is a modification of my previous answer to a question about executing terminal commands from within a JTextArea, but preventing the user from modifying the previously outputted text...
This version adds the ability to send text to the running process
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.StringJoiner;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.text.AbstractDocument;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.DocumentFilter;
public class QuickTerminal {
public static void main(String[] args) {
new QuickTerminal();
}
public QuickTerminal() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new ConsolePane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public interface CommandListener {
public void commandOutput(String text);
public void commandCompleted(String cmd, int result);
public void commandFailed(Exception exp);
}
public class ConsolePane extends JPanel implements CommandListener, Terminal {
private JTextArea textArea;
private int userInputStart = 0;
private Command cmd;
public ConsolePane() {
cmd = new Command(this);
setLayout(new BorderLayout());
textArea = new JTextArea(20, 30);
((AbstractDocument) textArea.getDocument()).setDocumentFilter(new ProtectedDocumentFilter(this));
add(new JScrollPane(textArea));
InputMap im = textArea.getInputMap(WHEN_FOCUSED);
ActionMap am = textArea.getActionMap();
Action oldAction = am.get("insert-break");
am.put("insert-break", new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
int range = textArea.getCaretPosition() - userInputStart;
try {
String text = textArea.getText(userInputStart, range).trim();
System.out.println("[" + text + "]");
userInputStart += range;
if (!cmd.isRunning()) {
cmd.execute(text);
} else {
try {
cmd.send(text + "\n");
} catch (IOException ex) {
appendText("!! Failed to send command to process: " + ex.getMessage() + "\n");
}
}
} catch (BadLocationException ex) {
Logger.getLogger(QuickTerminal.class.getName()).log(Level.SEVERE, null, ex);
}
oldAction.actionPerformed(e);
}
});
}
@Override
public void commandOutput(String text) {
SwingUtilities.invokeLater(new AppendTask(this, text));
}
@Override
public void commandFailed(Exception exp) {
SwingUtilities.invokeLater(new AppendTask(this, "Command failed - " + exp.getMessage()));
}
@Override
public void commandCompleted(String cmd, int result) {
appendText("\n> " + cmd + " exited with " + result + "\n");
appendText("\n");
}
protected void updateUserInputPos() {
int pos = textArea.getCaretPosition();
textArea.setCaretPosition(textArea.getText().length());
userInputStart = pos;
}
@Override
public int getUserInputStart() {
return userInputStart;
}
@Override
public void appendText(String text) {
textArea.append(text);
updateUserInputPos();
}
}
public interface UserInput {
public int getUserInputStart();
}
public interface Terminal extends UserInput {
public void appendText(String text);
}
public class AppendTask implements Runnable {
private Terminal terminal;
private String text;
public AppendTask(Terminal textArea, String text) {
this.terminal = textArea;
this.text = text;
}
@Override
public void run() {
terminal.appendText(text);
}
}
public class Command {
private CommandListener listener;
private ProcessRunner runner;
public Command(CommandListener listener) {
this.listener = listener;
}
public boolean isRunning() {
return runner != null && runner.isAlive();
}
public void execute(String cmd) {
if (!cmd.trim().isEmpty()) {
List<String> values = new ArrayList<>(25);
if (cmd.contains("\"")) {
while (cmd.contains("\"")) {
String start = cmd.substring(0, cmd.indexOf("\""));
cmd = cmd.substring(start.length());
String quote = cmd.substring(cmd.indexOf("\"") + 1);
cmd = cmd.substring(cmd.indexOf("\"") + 1);
quote = quote.substring(0, cmd.indexOf("\""));
cmd = cmd.substring(cmd.indexOf("\"") + 1);
if (!start.trim().isEmpty()) {
String parts[] = start.trim().split(" ");
values.addAll(Arrays.asList(parts));
}
values.add(quote.trim());
}
if (!cmd.trim().isEmpty()) {
String parts[] = cmd.trim().split(" ");
values.addAll(Arrays.asList(parts));
}
for (String value : values) {
System.out.println("[" + value + "]");
}
} else {
if (!cmd.trim().isEmpty()) {
String parts[] = cmd.trim().split(" ");
values.addAll(Arrays.asList(parts));
}
}
runner = new ProcessRunner(listener, values);
}
}
public void send(String cmd) throws IOException {
runner.write(cmd);
}
}
public class ProcessRunner extends Thread {
private List<String> cmds;
private CommandListener listener;
private Process process;
public ProcessRunner(CommandListener listener, List<String> cmds) {
this.cmds = cmds;
this.listener = listener;
start();
}
@Override
public void run() {
try {
System.out.println("cmds = " + cmds);
ProcessBuilder pb = new ProcessBuilder(cmds);
pb.redirectErrorStream();
process = pb.start();
StreamReader reader = new StreamReader(listener, process.getInputStream());
// Need a stream writer...
int result = process.waitFor();
// Terminate the stream writer
reader.join();
StringJoiner sj = new StringJoiner(" ");
cmds.stream().forEach((cmd) -> {
sj.add(cmd);
});
listener.commandCompleted(sj.toString(), result);
} catch (Exception exp) {
exp.printStackTrace();
listener.commandFailed(exp);
}
}
public void write(String text) throws IOException {
if (process != null && process.isAlive()) {
process.getOutputStream().write(text.getBytes());
process.getOutputStream().flush();
}
}
}
public class StreamReader extends Thread {
private InputStream is;
private CommandListener listener;
public StreamReader(CommandListener listener, InputStream is) {
this.is = is;
this.listener = listener;
start();
}
@Override
public void run() {
try {
int value = -1;
while ((value = is.read()) != -1) {
listener.commandOutput(Character.toString((char) value));
}
} catch (IOException exp) {
exp.printStackTrace();
}
}
}
public class ProtectedDocumentFilter extends DocumentFilter {
private UserInput userInput;
public ProtectedDocumentFilter(UserInput userInput) {
this.userInput = userInput;
}
public UserInput getUserInput() {
return userInput;
}
@Override
public void insertString(FilterBypass fb, int offset, String string, AttributeSet attr) throws BadLocationException {
if (offset >= getUserInput().getUserInputStart()) {
super.insertString(fb, offset, string, attr);
}
}
@Override
public void remove(FilterBypass fb, int offset, int length) throws BadLocationException {
if (offset >= getUserInput().getUserInputStart()) {
super.remove(fb, offset, length); //To change body of generated methods, choose Tools | Templates.
}
}
@Override
public void replace(FilterBypass fb, int offset, int length, String text, AttributeSet attrs) throws BadLocationException {
if (offset >= getUserInput().getUserInputStart()) {
super.replace(fb, offset, length, text, attrs); //To change body of generated methods, choose Tools | Templates.
}
}
}
}
So, I wrote myself a very simple Windows batch file...
@echo off
@echo Hello World!
set /p pathName=Enter The Value:%=%
@echo %pathName%
It doesn't do much, it outputs "Hello World!" and prompts the user to enter a value, which is further echoed to the screen and then terminates...
And used it to test the above code...

ProcessBuilderoverRuntime.exec, it's more configurable. Basically, you need to someway to process the output separately from the input. You might also need someway to know when input is required, so you're not allow the user to type things when it's not required, but that would come down more to your own needs