【问题标题】:JSch: Is there a way to expose user environment variables to "exec" channel?JSch:有没有办法将用户环境变量暴露给“exec”通道?
【发布时间】:2023-03-07 12:59:01
【问题描述】:

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

在下面添加我的课程代码:

    
    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();
    }
}

【问题讨论】:

    标签: java ssh jsch


    【解决方案1】:

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

    【讨论】:

      【解决方案2】:

      默认情况下,JSch 中的“exec”通道(正确地)不为会话分配伪终端 (PTY)。因此,(可能)获取了一组不同的启动脚本。和/或脚本中的不同分支基于TERM 环境变量的缺失/存在而被采用。因此,环境可能与交互式 JSch“shell”会话或您使用 SSH 客户端时不同。


      解决方法:

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

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

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

        使用伪终端自动执行命令会给您带来讨厌的副作用。见例子


      关于类似问题,请参阅

      【讨论】:

      • 我尝试将 pty 设置为 true,并使用下面给出的命令在远程服务器中运行环境脚本,但我仍然无法使用其他可用的逻辑路径。我使用的命令是“sh environment.sh && env”
      • @user3221714: sh environment.sh &amp;&amp; env 创建一个新的 shell 进程,称为 sh#2,它执行脚本 environment.sh,它可能会设置一些环境变量。 sh#2 然后成功退出,其内存被丢弃。原始 shell 然后创建一个env 进程,该进程看到原始 shell 的未更改的一组环境变量。如果您希望脚本在 same shell 进程中设置环境变量(或其他变量),请使用 source.,具体取决于您使用的 shell。这实际上是 shell 对其启动文件(即配置文件)所做的事情,尽管 哪些 启动文件因 shell 而异。
      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-11-24
        • 1970-01-01
        • 2019-07-19
        • 2018-02-16
        • 1970-01-01
        • 1970-01-01
        • 2018-06-09
        相关资源
        最近更新 更多