我有一个用于连接 SSH shell 的程序。我能够执行命令并读取它们的输出。
但我有一个新要求。现在我需要执行一个命令并读取输出(如果成功执行下一个命令)。
我使用了这个问题中的程序:JSch issue - Cannot retrieve full command output
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.setPty(false);
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();
}
}
我需要使用“shell” channel 而不是“exec”,因为服务器不允许“exec” channel :link
最佳答案
一般来说,您应该为此使用“exec” channel 。 “shell” channel 不应用于自动执行命令。
但我了解到您的服务器不支持“exec” channel 。 我为其他读者添加了上述评论,不要尝试使用此解决方案,除非他们确实必须这样做。
<小时/>正如 @Yair Harel 已经评论过的,如果你必须使用“shell” channel ,你就必须使用 shell 技术。
因此,在您的特定情况下,您可能希望远程 shell 在命令完成后打印一些唯一的字符串和退出代码:
out.println(command + " ; echo Command-has-finished-with-code-$?");
然后继续阅读输出,直到找到以 “Command-has-finished-with-code-”
开头的行。您解析退出代码并决定如何继续。
请注意,命令语法(特别是命令分隔符 ;
和退出代码变量 $?
)是特定于操作系统和 shell 的。由于您的服务器不是标准类型,因此语法可能会有所不同。
旁注:
“#!/bin/bash”
纯粹是无稽之谈。 shell 会忽略所有以#
开头的命令(它是注释)。寄出去也没啥意义- 请勿使用
StrictHostKeyChecking=no
。请参阅JSch SFTP security with session.setConfig("StrictHostKeyChecking", "no");
关于java - JSch Shell channel 执行命令一一测试结果再继续,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35533825/