带有 JSHh:非'simple'命令输出尾随意外输出,这些输出组合自正在使用的命令片段



我正在使用 jcraft.jsch 通道在 ssh 上运行几个命令,我看到每当我使用一些复杂的命令(使用 regexp 或使用管道)时,命令的输出都有一个意想不到的"前缀",该前缀由命令片段组合而成,或者整个命令被分割成用多个空格分隔的小块,并在这里和那里与"<"字符组合......

示例 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;
                }
            }
        }
    }

请告知

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

您正在打开一个通常用于交互式会话的 shell 通道。然后,将命令字符串写入通道的输入流,模拟键入命令的字符。这种运行命令的方式将起作用,但远程系统的行为就像这是一个交互式终端会话一样。特别是,远程 shell 可能会打印命令提示符,而远程 PTY 可能会回显程序正在"键入"的文本。我认为这就是发生在你身上的事情 - 你正在运行的命令的输出与命令提示符和字符回显混合在一起。

应考虑使用ChannelExec而不是ChannelShell来运行远程命令。使用ChannelExec,远程系统直接调用您的命令(而不是调用shell并让您将命令馈送到shell的输入中)。命令退出时通道关闭,不应为字符回显或命令提示符而烦恼。

Jsch有一个ChannelExec的例子。您的代码如下所示:

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()返回的流中读取。或者你可以用这些流做其他事情;请参阅示例。

最新更新