В чем разница между каналом 'shell' и каналом 'exec' в JSch - PullRequest
28 голосов
/ 21 июля 2011

Я хочу иметь возможность отправлять много последовательных команд, представленных в виде строк в приложении Java, на SSH-сервер для выполнения.Должен ли я использовать:

Channel channel = session.openChannel("shell");

-или-

Channel channel = session.openChannel("exec");

Ответы [ 4 ]

16 голосов
/ 21 июля 2011

С помощью канала оболочки запускается оболочка (в unix это sh или bash или что-то в этом роде, в Windows это обычно cmd.exe) и создается консоль (то же, что вы видите на экране, если запускаете их локально).У вас есть приглашение, которое вы можете проанализировать или использовать для обнаружения завершения команды.

При использовании командного канала экземпляр оболочки запускается для каждой команды (фактически канал открывается для каждой команды), а команда передается в качестве параметра для оболочки (в Windows это будет выглядеть как «cmd.exe /c ".

Командный канал проще использовать, поскольку вам не нужно иметь дело с командной строкой.

15 голосов
/ 21 июля 2011

Обзор различий и сходств между этими потоками вы можете найти в » Shell, Exec или Subsystem Channel « в вики JSch.Вот некоторые подробности для вашего варианта использования.

В канале exec команды приходят из командной строки, которую вы дали с помощью setCommand().Сервер SSH сразу же передаст их оболочке (используя что-то вроде bash -c '<command>').

Все они будут выполнены, если по какой-то причине оболочка по каким-либо причинам не завершится.(Вы можете отправить здесь целый сценарий оболочки, который реализует некоторую логику, используя if и аналогичные, если это необходимо.)

Таким образом, чтобы выполнить несколько команд, вы можете передать их в канал exec, разделив ихс ; или переводом строки (\n).Поскольку вы не можете дождаться результатов, прежде чем дать все команды, здесь вы можете использовать только несколько каналов exec (но, поскольку каждый канал порождает новую оболочку, они не сохраняют состояние между ними, например, рабочий каталог или переменные оболочки).

В канале shell оболочка будет считывать ввод из потока и интерпретировать первую строку как команду (или несколько).

Тогда он выполнит эту команду.Сама команда может прочитать дополнительные входные данные из потока, если она этого захочет.

Затем оболочка прочитает следующую строку, интерпретирует ее как команду и выполнит.

(В некоторых случаяхОболочка должна прочитать более одной строки, например, для длинных строк или составных команд, таких как циклы if или.)

Это будет продолжаться до конца потока (например, stream.close () на вашей стороне).) или выполнение явной команды выхода.

Если вы не отправляете какой-либо ввод в оболочку через канал ввода / вывода каналов, оболочка просто будет ждать, пока вы не отправите еще или закроете поток.Таким образом, вы можете спокойно прочитать вывод одной команды, выполнить некоторые вычисления на стороне клиента и затем решить, какую команду отправлять следующей.

Просто убедитесь, что вы не смешиваете ввод одной команды с текстом команды.следующая команда - желательно не использовать команды, которые будут считываться со стандартного ввода.

6 голосов
/ 21 июля 2011

хорошо, я обнаружил, что это работает, и это действительно удобно, если вы хотите сохранить состояние, как обычная оболочка:

Session session = jsch.getSession(user, host, 22);

Channel channel = session.openChannel("shell");

OutputStream inputstream_for_the_channel = channel.getOutputStream();
PrintStream commander = new PrintStream(inputstream_for_the_channel, true);

channel.setOutputStream(System.out, true);

channel.connect();

commander.println("ls -la");    
commander.println("cd folder");
commander.println("ls -la");
commander.println("exit");
commander.close();

do {
    Thread.sleep(1000);
} while(!channel.isEOF());

session.disconnect();

Вы можете изменить

channel.setOutputStream(System.out, true);

с помощью

InputStream outputstream_from_the_channel = channel.getInputStream();
BufferedReader br = new BufferedReader(new InputStreamReader(outputstream_from_the_channel));
String line;
while ((line = br.readLine()) != null)
    System.out.print(line+"\n");

, если вы хотите больше контроля над выходом.

============================================================================

РЕДАКТИРОВАНИЕ: проследить за

, почему иногда команды, которые я посылаю через PrintStream, случайно появляются в выходных данных.то есть следующий код:

shell[0].println("cd ..");
shell[0].println("cd ..");
shell[0].println("ls -la");
shell[0].println("exit");

производит это: (отмечены {вещь} вещи, которые не должны быть там!)

Последний вход в систему: чт 21 июля 21:49:13 2011 г. от шлюза

Манифесты: последний ствол

[host ~] $ cd ..
{cd ..} [host home] $
[host home] $cd ..
[host /] $
[host /] $ ls -la
{exit}

всего 9999
---------- 27корень корень 4096 26 января 2010 года.
---------- 27 корень корень 4096 янв 26 2010 ..
---------- 1 корень корня 0 марта 14 19:16 .autojyk
---------- 1 корневой корень 0 9 февраля 2009 г. .automan
---------- 1 корневой root 3550 14 мая 2010 .bash_history
d --------- 2 root root 4096 26 апреля 04:02 put
d --------- 5 root root 4024 25 апреля 19:31 boot
[m [host/] $
[host /] $ exit
Выйти

0 голосов
/ 22 июня 2019

Дело не в JSch. Речь идет о том, как сервер реализует два канала.


В общем * nix OpenSSH сервер:

  • Канал shell запускает оболочку входа в систему (как если вы входите в систему с помощью клиента терминала SSH). Затем оболочка представит командную строку и подождет, пока клиент / пользователь введет команды. Назначение канала shell - реализовать сеанс интерактивной оболочки. Это то, что каждый будет делать очень очень редко. Если вы это сделаете, вы, как правило, хотите использовать эмуляцию терминала.

    Канал shell, очевидно, используется клиентами терминала SSH (например, OpenSSH ssh или PuTTY) при нормальных обстоятельствах.

    Канал shell - это черный ящик с входом и выходом. Вход и выход не имеют структуры. Если вы, например, выполните команду, отправив ее на вход, вы никогда не сможете определить, когда она закончилась. Если вы отправите две команды во входную очередь, вы не сможете отличить, какие выходные данные поступают от какой команды.

  • Команда exec принимает команду в качестве «аргумента» и выполняет ее в изолированной среде & ndash; по-прежнему через пользовательскую оболочку по умолчанию, но не в качестве оболочки «входа», что может вызвать значительные различия в выполнении команды

    Назначение канала exec - автоматизировать выполнение команды. Поэтому, как правило, вы не хотите использовать эмуляцию терминала, чтобы избежать использования команды для создания таких причудливых вещей, как нумерация страниц, раскраска и в основном интерактивные подтверждения.

    exec канал используется OpenSSH ssh или PuTTY plink, когда вы указываете команду для выполнения в командной строке:

    ssh user@host command
    

С менее распространенными SSH-серверами разница может быть еще более существенной. Некоторые серверы могут даже не поддерживать один из каналов. Также довольно часто они, кажется, поддерживают оба, но один из них (обычно exec) полностью сломан.


Есть аналогичный вопрос для Python / Paramiko:
В чем разница между exec_command и send с invoke_shell () в Paramiko?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...