java - 使用 JSch Java 分离使用 PTY 执行的命令 (sudo) 的标准输出和错误输出
问题描述
我正在使用 Jsch,我的任务是登录服务器并运行以下命令
sudo "command"
使用以下代码,我可以成功连接并执行命令(没有错误"sudo: sorry, you must have a tty")
public String runSudo(RemoteHost remoteHost, String[] commands, OperationData operationData, String known_hosts, String id_rsa) {
String result = "";
Properties config = new Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
// Create a JSch session to connect to the server
Session session = null;
try {
session = jsch.getSession(remoteHost.getUsername(), remoteHost.getHost(), remoteHost.getPort());
if (remoteHost.getPassword() != null)
session.setPassword(remoteHost.getPassword());
else{
session.setConfig("PreferredAuthentications", "publickey");
jsch.setKnownHosts(known_hosts);
jsch.addIdentity(id_rsa);
}
session.setConfig(config);
// Establish the connection
session.connect();
logger.debug("Connected...");
for (int k = 0; k < commands.length; k++) {
ChannelExec channel = (ChannelExec) session.openChannel("exec");
channel.setCommand(commands[k]);
OutputStream outputStreamStdErr = new ByteArrayOutputStream();
channel.setErrStream(outputStreamStdErr, true);
channel.setPty(true);
InputStream in = channel.getInputStream();
channel.connect();
byte[] tmp = new byte[1024];
while (true) {
while (in.available() > 0) {
int i = in.read(tmp, 0, 1024);
if (i < 0) {
break;
}
result = result + new String(tmp, 0, i);
}
if (channel.isClosed()) {
this.exitStatus += channel.getExitStatus();
break;
}
Thread.sleep(1000);
}
String errors = readInputStream(outputstream2inputstream(outputStreamStdErr));
if (!errors.equals("")) {
operationData.setErrorMessage(errors);
}
channel.getErrStream().close();
channel.disconnect();
}
session.disconnect();
} catch (JSchException e) {
operationData.setErrorMessage(e.getMessage());
logger.error(e.getMessage());
return result;
} catch (IOException e) {
operationData.setErrorMessage(e.getMessage());
logger.error(e.getMessage());
return result;
} catch (InterruptedException e) {
operationData.setErrorMessage(e.getMessage());
logger.error(e.getMessage());
return result;
} finally {
return result;
}
}
但是使用该属性channel.setPty(true);
我无法读取错误流,因为它是null
并且错误显示在命令的输出中。相反,如果我不使用该属性channel.setPty(true);
,我可以读取错误流,但该方法返回错误“sudo:抱歉,您必须有一个 tty”,这是我想避免的。
有人可以帮助我channel.setPty(true);
在同一代码中使用错误流和属性吗?
解决方案
这是标准的 SSH 行为(至少在 Linux 上),当启用终端仿真时,所有输出都会进入 SSH 连接中的一个流。这与您的 Java/JSch 代码无关。
不要将 PTY 用于命令自动化。PTY 旨在实现一个供人类使用的交互式终端。
您可以配置sudo
为不需要 PTY。
还有其他选择。
请参阅
使用 SSH 在 Linux 上以 root 身份自动执行命令。
另一种解决方法是将标准输出和标准错误重定向到服务器上的临时文件。然后将文件分别打印到终端/输出。
一个简单的实现可以是:
sudo ... > /tmp/my_stdout 2> /tmp/my_stderr ; echo "stdout:" ; cat /tmp/my_stdout ; echo "stderr:" ; cat /tmp/my_stderr
推荐阅读
- python - 搜索游戏文件并增加替换 pid#
- html - 如何删除单击开关(使用复选框的html切换开关)时弹出并消失的背景蓝色?(找到解决方案)
- c - 如何并行计算 k 个集合位的所有组合?
- mysql - 如何在typeorm和nestjs中检索具有两个条件的数据
- function - 如何在 lua 表中调用未命名函数?[从桌子外面]
- python-3.x - 在 python3 Gtk 应用程序中监视文件的更改
- ssl - 使用练习 cli 时获取 tls 握手超时
- typescript - 如何将对象传递给打字稿中的函数?
- reactjs - 在前端显示指定列表
- android - Makefile 生成错误的符号链接