JSch:有没有办法将用户环境变量公开给 "exec" 频道?

JSch: Is there a way to expose user environment variables to "exec" channel?

我正在尝试 运行 使用本地 Linux 逻辑路径的命令,例如 cat $test_dir/test.dat,但逻辑路径 $test_dir(这是一个用户环境变量)是无法通过 ChannelExec 获得。但是当我使用交互式 ChannelShell 时,我能够在交互式会话中看到用户变量和命令 运行。我只能从“exec”会话中查看系统级环境变量。这甚至可以使用 JSch 库吗?如果是,我该如何实现它,如果不能,我应该使用什么库来实现它?

在下面添加我的 class 代码:

    
    private static final Logger logger = LogManager.getLogger(SecureShell.class);
    
    private String uName;
    private String pWord;
    private String hName;
    private int port;
    
    private Session session = null;
    private Channel channel = null;
    
    /**Create an instance to start and stop the remote shell and execute commands
     * remotely via java.
     * 
     * @param uName
     *          host username 
     * @param pWord
     *          host password
     * @param hName
     *          host name
     * @param port
     *          host port number
     */
    public SecureShell(String uName, String pWord, String hName, int port) {
        this.uName = uName;
        this.pWord = pWord;
        this.hName = hName;
        this.port = port;
    }
    
    /**Create an instance to start and stop the remote shell and execute commands
     * remotely via java.
     * 
     *@param uName
     *          host username 
     * @param pWord
     *          host password
     * @param hName
     *          host name
     */
    public SecureShell(String uName, String pWord, String hName) {
        this.uName = uName;
        this.pWord = pWord;
        this.hName = hName;
        this.port = 22;
    }
    
    /**Start the session with the host.
     * @return
     *      true if the session started successfully, false otherwise
     */
    public boolean startSession() {
        JSch jsch = new JSch();
        try {
            session = jsch.getSession(uName, hName, port);
            
            java.util.Properties config = new java.util.Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
            session.setPassword(pWord);
            session.connect();
            
        } catch (JSchException jsche) {
            logger.error(jsche.getMessage());
            return false;
        } 
        
        return true;
    }
    
    /** Execute commands on the host;
     * @param command
     *          command to be executed on the host.
     * @return
     *      status of the execution
     */
    public int execute(String command) {
        
        int status = -1;
        if(session != null && session.isConnected()) {
            try {
                channel = session.openChannel("exec");
                //((ChannelExec)channel).setEnv("LC_XXX", "xxxxxxx");
                ((ChannelExec)channel).setPty(true);
                ((ChannelExec) channel).setCommand(command);
                
                InputStream in = channel.getInputStream();
        
                channel.connect();
                
                 byte[] buffer = new byte[1024];
                 while(true){
                     while(in.available()>0){
                         int i=in.read(buffer, 0, 1024);
                         System.out.print(new String(buffer, 0, i));
                         if(i<0)
                             break;
                    }
                     if(channel.isClosed()){
                         if(in.available()>0) 
                             continue; 
                         status = channel.getExitStatus();
                         break;
                     }
                }
            } catch (JSchException jsche) {
                logger.error(jsche.getMessage());
            } catch (IOException ioe) {
                logger.error(ioe.getMessage());
            } finally {
                if(channel!=null && channel.isConnected())
                    channel.disconnect();
            } 
        }
        
        return status;
    }
    
    /**Stop the session with the remote.
     * 
     */
    public void stopSession() {
        
        if(session!=null && session.isConnected())
            session.disconnect();
    }
    
    public static void main(String[] args) {
        SecureShell ssh  = new SecureShell("user", "password", "hostname");
        ssh.startSession();
        System.out.println(ssh.execute("env"));
        ssh.stopSession();
    }
}

默认情况下,JSch 中的 "exec" 通道(理所当然地)不会为会话分配伪终端 (PTY)。因此,(可能)获得了一组不同的启动脚本。 And/or 根据 TERM 环境变量的 absence/presence,采用脚本中的不同分支。因此环境可能不同于交互式 JSch "shell" 会话或当您使用 SSH 客户端时。


解决此问题的方法:

  1. 修复您的启动脚本,为交互式和非交互式会话设置相同的环境变量。

  2. 另一种(不推荐)方法是使用.setPty方法强制为"exec"频道分配伪终端:

    Channel channel=session.openChannel("exec");
    ((ChannelExec)channel).setPty(true);
    

    使用伪终端自动执行命令会给您带来严重的副作用。参见示例

    • Remove of unwanted characters when i am using jsch to run command
    • Removing shell stuff (like prompts) from command output in JSch

对于类似的问题,请参阅

由于您没有打开交互式 shell,因此不会设置您的环境变量。但是,您可以将 bash 命令与 --login (man bash 以获得更多详细信息)一起使用以获得您想要的结果

bash --login -c 'command arg1 ...'"

我能够通过在 .bashrc 文件中设置环境变量来解决这个问题。通过 setEnv 方法设置环境变量对我没有帮助。