Подтвердить что ты не робот

В чем разница между каналом "shell" и каналом "exec" в JSch

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

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

-или -

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

Ответ 1

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

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

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

Ответ 2

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

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

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

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

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

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

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

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

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

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

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

Ответ 3

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

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");

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

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

EDITED: отслеживание

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

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

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

Последний вход: Чт Июл 21 21:49:13 2011 от шлюза

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

[host ~] $cd..
{cd..} [host home] $
[хозяин дома] $cd..
[host/] $
[host/] $ls -la
{exit}

всего 9999
---------- 27 корень root 4096 26 января 2010 г.
---------- 27 корень root 4096 26 января 2010 г.

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

Ответ 4

Это не так много о JSch. Это о том, как сервер реализует два канала.


В общих чертах * nix OpenSSH сервер:

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

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

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

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

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

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

    ssh [email protected] command
    

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


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