0

JSchを使用してJavaからリモートUnixホストに正常に接続し、いくつかの基本的なコマンドを実行したり、ファイルを表示したりすることができます。

問題は環境の設定から始まります...あるコマンドで変数をエクスポートすると、別のシェルで実行されているかのように、次のコマンドでは表示されません。私がやりたいのは、同じシェルで実行されている複数のコマンドをエミュレートすることです。

これが私のexecuteCommandメソッドです。これには、 openHostSession(下記)によって作成された以前に作成されたcom.jcraft.jsch.Sessionが必要です。

    public static void executeCommand(Session sess, String cmd, PrintStream pstream)
    {
        System.out.println("About to execute <" + cmd + ">");

        try
        {
            ChannelExec chnl = (ChannelExec)sess.openChannel("exec");     

            chnl.setInputStream(null);      

            chnl.setErrStream(System.err);  

            chnl.setCommand(cmd);      

            InputStream in = chnl.getInputStream();      

            chnl.connect();      

            byte[] tmp=new byte[1024];      

            while(true)
            {        
                while(in.available() > 0)
                {          
                    int i = in.read(tmp, 0, 1024); 

                    if(i < 0) break;          

                    pstream.print(new String(tmp, 0, i));        
                }        

                if(chnl.isClosed())
                {          
                    pstream.println("exit-status: " + chnl.getExitStatus());   

                    break;        
                }        

                try
                {
                    Thread.sleep(1000);
                }

                catch(Exception ee){}      
            }      

            chnl.disconnect();
        }
        catch(Exception ex)
        {
            ex.printStackTrace();
        }

    }

ここにopenHostSessionがあります:

public static Session openHostSession(String host, String user, String passwd)
    {
        JSch jsch=new JSch();
        Session rslt = null;

        try
        {
            rslt = jsch.getSession(user, host, 22);
            rslt.setConfig("StrictHostKeyChecking", "no"); 
            rslt.setPassword(passwd);
            rslt.connect(30000);   
        }
        catch(JSchException jschEx)
        {
            jschEx.printStackTrace();
        }

        return rslt;
    }

クライアントコード

cmd = "export XVAR=abc";
SshUtil.executeCommand(sess, cmd, System.out);

cmd = "echo $XVAR";
SshUtil.executeCommand(sess, cmd, System.out);

出力:

About to execute <export XVAR=abc>
exit-status: 0
About to execute <echo $XVAR>

exit-status: 0

システムレベルのenv変数を確認できます。例:

cmd = "echo $SHELL";
SshUtil.executeCommand(sess, cmd, System.out);

戻り値

About to execute <echo $SHELL>
/bin/ksh

終了ステータス:0

.profile(cmd = ". ./.profile";).profile内に設定された変数は次のコマンドでは表示されません。コマンドは同じセッションを共有しますが、それぞれが独自のチャネルを開きます。チャネルを共有しようとしましたが、うまくいきませんでした。

4

1 に答える 1

1

これが exec チャネルの仕組みです。SSH サーバーに対して単一のコマンドを実行し、各コマンドの実行は次のコマンドから独立しています。次のようなことをしたようです:

# ssh machine 'VAR=tmp; echo $VAR'
foo
# ssh machine 'echo $VAR'

これらは 2 つの別個のコマンド実行であるため、環境変数 VAR の設定は 2 番目のコマンドのコンテキストには存在しません (実行される 2 つのシェルであるため)。一連のコマンドを JSch でストリーミングしたい場合は、おそらく ChannelShell クラスを調べる必要があります。次のように呼び出すことで、それを利用できます。

ChannelShell chnl = (ChannelShell)sess.openChannel("shell");

これにより、一連のコマンドを実行し、最初のコマンドの結果が 2 番目のコマンドに影響を与えることができる長年の対話型シェルが開きます。ただし、これを使用するとかなり複雑になるため、「exec」のドロップイン代替ではありません。JSch ディストリビューションに付属するさまざまな例を確認することをお勧めします。それらの多くは openChanell("shell") 手法を使用しており、役立つ可能性があります。

于 2012-10-19T18:39:19.700 に答える