用JSch Java用PTY执行的命令(sudo)的标准输出和错误输出分开。

问题描述 投票:2回答:1

我使用的是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: sorry, you must have a tty" 我想避免的。

谁能帮助我使用错误流和属性--------。channel.setPty(true); 在相同的代码中?

java shell ssh sudo jsch
1个回答
1
投票

这是标准的SSH行为(至少在Linux上是这样),当终端仿真被启用时,所有的输出都会进入SSH连接中的一个流。这与你的JavaJSch代码无关。

不要使用PTY来实现命令自动化。PTY的目的是为了实现一个交互式终端,供人使用。

你可以配置 sudo 不要求PTY。

也有其他选择。见允许在Linux上使用SSH以root身份自动执行命令。.


另一个变通方法是将stdout和stderr重定向到服务器上的临时文件。然后分别打印这些文件到终端输出。

憨厚的实现方式可以是这样的。

sudo ... > /tmp/my_stdout 2> /tmp/my_stderr ; echo "stdout:" ; cat /tmp/my_stdout ; echo "stderr:" ; cat /tmp/my_stderr
© www.soinside.com 2019 - 2024. All rights reserved.