3

In my Java program what I am trying to do is:

First, I connect to a Unix server and execute one shell script. But in that shell script, you have to select the option to perform the different operation once the option is selected.

For example:

Please select from below menu options
1. Create directory and subdirectory
2. Copy files
3. Update paths
4. Press 9 to exit

Here each option performs different operations and upon selecting any asks for further input. For ex: If I select an option 1 it will ask for the path:

Please enter the path where you want to create a directory

Now my question is: How can I enter this input while running this shell script from Java code?

Below code is written For connecting to unix server and execution of shell script:

JSch jsch = new JSch();

String command = "/tmp/myscript.sh";
Session session = jsch.getSession(user, host, 22);
session.connect();

Channel channel = session.openChannel("exec");
((ChannelExec)channel).setCommand(command);

channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream in = channel.getInputStream();
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
channel.connect();

byte[] tmp = new byte[1024];
while (true) {
  while (in.available() > 0) {
      int i = in.read(tmp, 0, 1024);
      if (i < 0) {
          break;
      }
      System.out.print(new String(tmp, 0, i));
  }
  if (channel.isClosed()) {
      if (channel.getExitStatus() == 0) {
          System.out.println("Command executed successully.");
      }
      break;
  }
}
channel.disconnect();
session.disconnect();
5
  • Hi, could anybody please help here? Commented May 21, 2021 at 15:05
  • How do you want to get the input? A GUI? Something custom from your program? stdin (of your program)? In the last case, you could try channel.setInputStream(System.in);. Commented May 26, 2021 at 19:10
  • 1
    Why are you reading from your channel's input stream instead of writing to it? Commented May 26, 2021 at 19:11
  • 2
    BTW, it would be a better minimal reproducible example if instead of depending on a myscript.sh nobody but you has, you executed something like String[]{"bash", "-c", "read -p 'need input: ' input; echo \"got input: $input\""} -- that way your code wouldn't require dependencies it doesn't contain. Commented May 26, 2021 at 19:13
  • likely you can't, using shell select creates a interactive shell and holds stdin, and you are still try to glue back with java, why ? haha Commented Jun 1, 2021 at 13:13

2 Answers 2

2
+50

Let's say we want to "Create directory and subdirectory", then exit.
Once the channel is ready, we have to:

  1. send create command "1"
  2. send path "/path/to/directory"
  3. send exit command "9"
JSch jsch = new JSch();

String command = "/tmp/myscript.sh";
Session session = jsch.getSession(user, host, 22);
session.setConfig("StrictHostKeyChecking", "no");
session.setPassword(passwd);
session.connect();

ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setCommand(command);
channel.setInputStream(null);
channel.setErrStream(System.err);
InputStream is = channel.getInputStream();
// We will send commands through this stream
OutputStream os = channel.getOutputStream();
channel.connect();

int step = 1;
byte[] tmp = new byte[1024];
int read;
while (true) {
    // Wait for available data
    while(is.available() == 0) {
        Thread.sleep(100);
    }
    // Read the script/command output
    while(is.available() > 0) {
        read = is.read(tmp);
        if (read < 0) {
            break;
        }
        System.out.print(new String(tmp, 0, read));
    }
    // Send a command depending on current step
    switch(step) {
    case 1:
        // 1. Create directory command
        os.write("1\n".getBytes());
        os.flush();
        break;
    case 2:
        // 2. Path to create
        os.write("/path/to/directory\n".getBytes());
        os.flush();
        break;
    case 3:
        // 3. Exit command
        os.write("9\n".getBytes());
        os.flush();
        break;
    }
    step++;
    if (channel.isClosed()) {
        if (channel.getExitStatus() == 0) {
            System.out.println("Command executed successully.");
        }
        break;
    }
}
channel.disconnect();
session.disconnect();

The final "\n" and a call to os.flush are mandatory for each command.

Sign up to request clarification or add additional context in comments.

Comments

0

You can probably get away with printing to /dev/tty and reading from /dev/tty in your shell script. Wrap /tmp/myscript.sh like so:

#!/bin/bash
(
ORIGINAL_CODE_HERE
) < /dev/tty > /dev/tty

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.