2014-09-11 2 views
3

Я использую библиотеку JSch -SSH выполнить команду в канале «оболочка», но не смогли найти способ сделать 2 вещи: -Как получить JSch вывод команды оболочки в строках

1) Как найти, полностью ли выполнена команда в удаленном окне unix?

2) Как захватить вывод команды в String вместо того, чтобы печатать его на консоли System.out?

Ниже мой фрагмент кода, который прекрасно работает для отображения вывода команды оболочки на System.out

Примечание: Я не хочу использовать «EXEC» канал, как он запускает новый процесс для каждой команды и делает не помнят переменные «сессии», которые были экспортированы. Я должен использовать канал «shell».

Ниже приведен фрагмент кода. Любая помощь приветствуется. Спасибо за ваше время.

try{ 

    String commandToRun = "ls /tmp/*.log \n"; 
    if(channel.isClosed()) 
     channel=session.openChannel("shell"); 
    byte[] bytes = commandToRun.getBytes(); 
    ByteArrayInputStream bais=new ByteArrayInputStream(bytes); 
    channel.setInputStream(bais); 
    InputStream ins=channel.getInputStream(); 
    channel.connect(); 
    channel.setOutputStream(System.out);//This prints on console. Need 2 capture in String somehow? 

    //in-efficient way to allow command to execute completely on remote Unix machine 
    //DO NOT know a better way, to know when command is executed completely 
    Thread.sleep(5000L); 
} 
catch(Exception e){ 
    System.out.println("Exception in executeCommand() --->"+ e.getMessage()); 
    e.printStackTrace(); 
} 
+0

http://stackoverflow.com/a/25845360/1917804 –

+0

Вы вообще не должны использовать канал «оболочки», чтобы автоматизировать выполнение команды. Вместо этого используйте канал «exec». См. [Выполнение списка команд из ArrayList с использованием JSch exec в Java] (http://stackoverflow.com/q/34825155/850848). Если вы используете канал «shell», вы рано или поздно попадаете в неприятности.См. Один пример возможных проблем из многих, см. [Проблема JSch - Не удается получить полный вывод команды] (http://stackoverflow.com/q/35502600/850848) –

ответ

6

Для 2) и может использовать ByteArrayOutputStream

final ByteArrayOutputStream baos = new ByteArrayOutputStream(); 
channel.setOutputStream(baos); 

, а затем создать новую строку из new String(baos.toByteArray())

За 1 вы пытались использовать 2> & 1 в конце вашей команды?

String commandToRun = "ls /tmp/*.log 2>&1 \n"; 
+0

Спасибо Nikola за ваш ответ. Я также нашел ByetArrayOutputStream до того, как я видел ваш комментарий, он работает. Что касается Ques1. Я не пробовал подход, который вы упомянули, но попробует. Еще раз. – vishy

11

Мое решение не может понадобиться больше для ОП, но кто-то, кто ищет решения, чтобы покрыть оба условия 1), ожидающие команды, чтобы закончить на удаленном компьютере; и 2) захват вывода как строки; Вы можете попробовать это:

public class SshConnectionManager { 

private static Session session; 
private static ChannelShell channel; 
private static String username = ""; 
private static String password = ""; 
private static String hostname = ""; 


private static Session getSession(){ 
    if(session == null || !session.isConnected()){ 
     session = connect(hostname,username,password); 
    } 
    return session; 
} 

private static Channel getChannel(){ 
    if(channel == null || !channel.isConnected()){ 
     try{ 
      channel = (ChannelShell)getSession().openChannel("shell"); 
      channel.connect(); 

     }catch(Exception e){ 
      System.out.println("Error while opening channel: "+ e); 
     } 
    } 
    return channel; 
} 

private static Session connect(String hostname, String username, String password){ 

    JSch jSch = new JSch(); 

    try { 

     session = jSch.getSession(username, hostname, 22); 
     Properties config = new Properties(); 
     config.put("StrictHostKeyChecking", "no"); 
     session.setConfig(config); 
     session.setPassword(password); 

     System.out.println("Connecting SSH to " + hostname + " - Please wait for few seconds... "); 
     session.connect(); 
     System.out.println("Connected!"); 
    }catch(Exception e){ 
     System.out.println("An error occurred while connecting to "+hostname+": "+e); 
    } 

    return session; 

} 

private static void executeCommands(List<String> commands){ 

    try{ 
     Channel channel=getChannel(); 

     System.out.println("Sending commands..."); 
     sendCommands(channel, commands); 

     readChannelOutput(channel); 
     System.out.println("Finished sending commands!"); 

    }catch(Exception e){ 
     System.out.println("An error ocurred during executeCommands: "+e); 
    } 
} 

private static void sendCommands(Channel channel, List<String> commands){ 

    try{ 
     PrintStream out = new PrintStream(channel.getOutputStream()); 

     out.println("#!/bin/bash"); 
     for(String command : commands){ 
      out.println(command); 
     } 
     out.println("exit"); 

     out.flush(); 
    }catch(Exception e){ 
     System.out.println("Error while sending commands: "+ e); 
    } 

} 

private static void readChannelOutput(Channel channel){ 

    byte[] buffer = new byte[1024]; 

    try{ 
     InputStream in = channel.getInputStream(); 
     String line = ""; 
     while (true){ 
      while (in.available() > 0) { 
       int i = in.read(buffer, 0, 1024); 
       if (i < 0) { 
        break; 
       } 
       line = new String(buffer, 0, i); 
       System.out.println(line); 
      } 

      if(line.contains("logout")){ 
       break; 
      } 

      if (channel.isClosed()){ 
       break; 
      } 
      try { 
       Thread.sleep(1000); 
      } catch (Exception ee){} 
     } 
    }catch(Exception e){ 
     System.out.println("Error while reading channel output: "+ e); 
    } 

} 

public static void close(){ 
    channel.disconnect(); 
    session.disconnect(); 
    System.out.println("Disconnected channel and session"); 
} 


public static void main(String[] args){ 
    List<String> commands = new ArrayList<String>(); 
    commands.add("ls -l"); 

    executeCommands(commands); 
    close(); 
} 
} 

Это решение также полезно, если вам нужно отправить несколько команд одновременно и держать канал открытым, чтобы использовать его позже.

+0

Обычно вам не нужно использовать канал «shell» для автоматизации выполнения команды. Вместо этого используйте канал «exec». См. [Выполнение списка команд из ArrayList с использованием JSch exec в Java] (http://stackoverflow.com/q/34825155/850848). Если вы используете канал «shell», вы рано или поздно попадаете в неприятности. См. Один пример возможных проблем из многих, см. [Проблема JSch - Не удается получить полный вывод команды] (http://stackoverflow.com/q/35502600/850848) –

+0

Не используйте 'StrictHostKeyChecking = no'. См. [Безопасность JSch SFTP с session.setConfig («StrictHostKeyChecking», «no»);] (http://stackoverflow.com/q/30178936/850848). –

+0

«out.println (« #!/Bin/bash »);' является чистой бессмыслицей. Оболочка игнорирует все команды, начинающиеся с '#' (это комментарий). Нет смысла посылать его. –

1

Взяв пример, предоставленный Михаилом, другую информацию о интернетах и ​​отзывы от Мартина, вот переработанное решение с использованием exec. Обратите внимание, что открытие сеанса позволяет отправлять несколько команд, каждый из которых открывает собственный канал для ввода/вывода.

Рант: Я действительно не люблю того, чтобы начать процесс OUTPUT потока на запись. Какая раздражающая парадигма (по крайней мере для меня). То, что я хотел, - это поток входных процессов, чтобы написать мой вывод, и у него было невероятно трудное время, чтобы понять, что оно инвертировано. Является ли это только мной или делает следующее (псевдокод), чтобы не сделать больше смысла?

channel.getInputStream().write("here's some text to write into my channel.");

String ret = channel.getOutputStream().getOutput();

В любом случае, спасибо Mihail и Мартина за их комментарии/вход.

public class SSHConnectionManager { 

    private Session session; 

    private String username = "user"; 
    private String password = "password"; 
    private String hostname = "myhost"; 

    public SSHConnectionManager() { } 

    public SSHConnectionManager(String hostname, String username, String password) { 
     this.hostname = hostname; 
     this.username = username; 
     this.password = password; 
    } 

    public void open() throws JSchException { 
     open(this.hostname, this.username, this.password); 
    } 

    public void open(String hostname, String username, String password) throws JSchException{ 

     JSch jSch = new JSch(); 

     session = jSch.getSession(username, hostname, 22); 
     Properties config = new Properties(); 
     config.put("StrictHostKeyChecking", "no"); // not recommended 
     session.setConfig(config); 
     session.setPassword(password); 

     System.out.println("Connecting SSH to " + hostname + " - Please wait for few seconds... "); 
     session.connect(); 
     System.out.println("Connected!"); 
    } 

    public String runCommand(String command) throws JSchException, IOException { 

     String ret = ""; 

     if (!session.isConnected()) 
      throw new RuntimeException("Not connected to an open session. Call open() first!"); 

     ChannelExec channel = null; 
     channel = (ChannelExec) session.openChannel("exec"); 

     channel.setCommand(command); 
     channel.setInputStream(null); 

     PrintStream out = new PrintStream(channel.getOutputStream()); 
     InputStream in = channel.getInputStream(); // channel.getInputStream(); 

     channel.connect(); 

     // you can also send input to your running process like so: 
     // String someInputToProcess = "something"; 
     // out.println(someInputToProcess); 
     // out.flush(); 

     ret = getChannelOutput(channel, in); 

     channel.disconnect(); 

     System.out.println("Finished sending commands!"); 

     return ret; 
    } 


    private String getChannelOutput(Channel channel, InputStream in) throws IOException{ 

     byte[] buffer = new byte[1024]; 
     StringBuilder strBuilder = new StringBuilder(); 

     String line = ""; 
     while (true){ 
      while (in.available() > 0) { 
       int i = in.read(buffer, 0, 1024); 
       if (i < 0) { 
        break; 
       } 
       strBuilder.append(new String(buffer, 0, i)); 
       System.out.println(line); 
      } 

      if(line.contains("logout")){ 
       break; 
      } 

      if (channel.isClosed()){ 
       break; 
      } 
      try { 
       Thread.sleep(1000); 
      } catch (Exception ee){} 
     } 

     return strBuilder.toString(); 
    } 

    public void close(){   
     session.disconnect(); 
     System.out.println("Disconnected channel and session"); 
    } 


    public static void main(String[] args){ 

     SSHConnectionManager ssh = new SSHConnectionManager(); 
     try { 
      ssh.open(); 
      String ret = ssh.runCommand("ls -l"); 

      System.out.println(ret); 
      ssh.close(); 

     } catch (Exception e) { 
      // TODO Auto-generated catch block 
      e.printStackTrace(); 
     } 
    } 
} 
+0

Ошибка копирования-вставки. Я уберу. – gdbj

Смежные вопросы