带有jsch的ssh:非'简单'命令输出跟随使用中命令片段的意外输出

时间:2014-11-27 10:43:35

标签: java linux ssh jsch

我使用jcraft.jsch频道在ssh上运行了几个命令,我看到每当我使用一些复杂的命令(使用regexp或使用管道)时,命令的输出都有一个意外的'前缀&#39 ;从命令的片段或整个命令组合成碎片,分成多个空格分隔的小片,并与''<&#人物到处......

示例1:

#ls /opt/qb/data2/oscar/process-manager-helper/*/var/core-dump/{2089,2090,2091,2092,2093,2094,2095}.*

ger-helper/*/var/core-dump/{20

<2/oscar/process-manager-helper/*/var/core-dump/{208                         9,2090,2091,2092,ls: cannot access /opt/qb/data2/oscar/process-manager-helper/*/var/core-dump/2090.*: No such file or directory
ls: cannot access /opt/qb/data2/oscar/process-manager-helper/*/var/core-dump/2092.*: No such file or directory
ls: cannot access /opt/qb/data2/oscar/process-manager-helper/*/var/core-dump/2094.*: No such file or directory
ls: cannot access /opt/data2/oscar/process-manager-helper/*/var/core-dump/2095.*: No such file or directory
/opt/qb/data2/oscar/process-manager-helper/0/var/core-dump/2089.20141126-195527.213-00000000-opt.dell.srvadmin.bin.idracadm7.idracadm7.core.gz
/opt/qb/data2/oscar/process-manager-helper/0/var/core-dump/2091.20141126-201557.530-00000000-opt.dell.srvadmin.bin.idracadm7.idracadm7.core.gz
/opt/qb/data2/oscar/process-manager-helper/0/var/core-dump/2093.20141126-202822.524-00000000-opt.dell.srvadmin.bin.idracadm7.idracadm7.core.gz

示例2:

#du -s --block-size=1 /opt/qb/data2/oscar/process-manager-helper/0/var/core-dump/2089.20141126-195527.213-00000000-opt.dell.srvadmin.bin.idracadm7.idracadm7.core.gz | awk { print $1; }

rvadmin.bin.idracad

<-195527.213-00000000-opt.dell.srvadmin.bin.idracadm                         7.idracadwk

<ell.srvadmin.bin.idracadm7.idracadm7.core.gz | awk                          { print $1; }
86016

这是一个重现它的示例代码(至少在我的设置中):

public static void main(String[] args) throws Exception
    {
        JSch myConnection = new JSch();
        myConnection.setKnownHosts("/dev/null");
        Session mySession = myConnection.getSession("root", "my-host.my-lab.com", 2222);
        mySession.setPassword("password123");
        Properties config = new Properties();
        config.put("StrictHostKeyChecking", "no");
        mySession.setConfig(config);
        mySession.connect(15000);
        Channel myChannel = mySession.openChannel("shell");

        ((ChannelShell) myChannel).setPtyType("exec");
        InputStream fromServer = myChannel.getInputStream();
        OutputStream toServer = myChannel.getOutputStream();

        myChannel.connect();

        String commandString = "du -s --block-size=1 /opt/base/dir/eventLog | awk '{ print $1; }'";
        toServer.write((commandString + "\n").getBytes());
        toServer.flush();

        Thread.sleep(5000);

        StringBuffer result = new StringBuffer();

        while (true)
        {
            int avail = fromServer.available();
            if (avail > 0)
            {
                while (avail > 0)
                {
                    byte[] buf = new byte[avail];
                    int bytesRead = 0;
                    if ((bytesRead = fromServer.read(buf)) < 0)
                    {
                        throw new IOException("connection is probably closed (can't read " + avail + " from server) - return value is " + bytesRead);
                    }
                    for (int i = 0; i < bytesRead; i++)
                    {
                        if (buf[i] >= 127 || buf[i] < 9 || (buf[i] >= 14 && buf[i] <= 31) || buf[i] == 11 || buf[i] == 12 || buf[i] == 8)
                        {
                            continue;
                        }
                        result.append((char) buf[i]);
                    }
                    avail = fromServer.available();
                }
                if (result.toString().trim().endsWith("#"))
                {
                    System.out.println(result);
                    break;
                }
            }
        }
    }

请告知

1 个答案:

答案 0 :(得分:0)

Channel myChannel = mySession.openChannel("shell");
((ChannelShell) myChannel).setPtyType("exec");
[...]
String commandString = "du ...";
toServer.write((commandString + "\n").getBytes());

您正在打开一个shell频道,该频道通常用于互动会话。然后,您将命令字符串写入通道的输入流,该输入流模拟键入命令的字符。这种运行命令的方式可行,但远程系统的行为就好像这是一个交互式终端会话。特别是,远程shell可以打印命令提示,远程PTY可以回显你的程序所在的文本&#34;输入&#34;。我认为发生了什么 - 你正在运行的命令的输出与命令提示和字符回声混合在一起。

您应该考虑使用ChannelExec来运行远程命令而不是ChannelShell。使用ChannelExec,远程系统直接调用您的命令(而不是调用shell并让您将命令提供给shell的输入)。当命令退出时,通道关闭,你不应该受到字符回显或命令提示的困扰。

Jsch有ChannelExec example。您的代码看起来像这样:

ChannelExec chan = mySession.openChannel("exec");
chan.setCommand("du ... | awk ...");
// Set input and output streams
// Request a PTY if you think you need one
chan.connect();

chan.connect()将打开频道并在远程系统上启动命令。可以从getInputStream()返回的输入流中读取远程命令的标准输出,并且可以从getErrStream()返回的流中读取命令的标准错误。或者你可以用这些流做其他事情;看到例子。