當使用JSch通過Java執行時,某些Unix命令失敗並顯示“... not found”




shell ssh (2)

我有一段連接到Unix服務器並執行命令的代碼。

我一直在嘗試簡單的命令,他們工作正常。

我能夠登錄並獲得命令的輸出。

我需要通過Java運行Ab-initio圖。

我正在使用 air sandbox run graph 命令。

當我使用SSH客戶端登錄並運行命令時,它運行正常。 我能夠運行圖表。 但是,當我嘗試通過Java運行命令時,它會給我一個 “未找到空氣”的 錯誤。

對JSch支持的Unix命令有什麼限制嗎?

知道為什麼我無法通過我的Java代碼運行命令嗎?

這是代碼:

public static void connect(){
    try{
      JSch jsch=new JSch();  

      String host="*****";
      String user="*****";
      String config =
                "Host foo\n"+
                "  User "+user+"\n"+
                "  Hostname "+host+"\n";

      ConfigRepository configRepository =
            com.jcraft.jsch.OpenSSHConfig.parse(config);

      jsch.setConfigRepository(configRepository);
      Session session=jsch.getSession("foo");

      String passwd ="*****";
      session.setPassword(passwd);
      UserInfo ui = new MyUserInfo(){

          public boolean promptYesNo(String message){

            int foo = 0;
            return foo==0;
          }
      };
      session.setUserInfo(ui);
      session.connect();

      String command="air sandbox run <graph-path>";

      Channel channel=session.openChannel("exec");
      ((ChannelExec)channel).setCommand(command);

      channel.setInputStream(null);

      ((ChannelExec)channel).setErrStream(System.err);

      InputStream in=channel.getInputStream();

      channel.connect();

      byte[] tmp=new byte[1024];
      while(true){
        while(in.available()>0){
          int i=in.read(tmp, 0, 1024);
          if(i<0)break;
          page_message=new String(tmp, 0, i);
          System.out.print(page_message);
        }
        if(channel.isClosed()){
          if(in.available()>0) continue; 
          System.out.println("exit-status: "+channel.getExitStatus());
          break;
        }
        try{Thread.sleep(1000);}catch(Exception ee){}
      }

      channel.disconnect();
      session.disconnect();
    }
    catch(Exception e){
      System.out.println(e);
    }
}

public static void main(String arg[]){
    connect();
}

public String return_message(){
      String ret_message=page_message;
      return ret_message;
}

public static abstract class MyUserInfo
    implements UserInfo, UIKeyboardInteractive{
    public String getPassword(){ return null; }
    public boolean promptYesNo(String str){ return false; }
    public String getPassphrase(){ return null; }
    public boolean promptPassphrase(String message){ return false; }
    public boolean promptPassword(String message){ return false; }
    public void showMessage(String message){ }
    public String[] promptKeyboardInteractive(String destination,
                        String name,
                        String instruction,
                        String[] prompt,
                        boolean[] echo){
        return null;
    }
}

JSch中的“exec”通道(正確地)不為會話分配偽終端(PTY)。 因此,(可能)獲取了一組不同的啟動腳本(特別是對於非交互式會話,不提供 .bash_profile )。 和/或腳本中的不同分支基於 TERM 環境變量的缺失/存在而被採用。 所以環境可能與交互式會話不同,您可以使用SSH客戶端。

因此,在您的情況下, PATH 可能設置不同; 因此無法找到 air 可執行文件。

要驗證這是根本原因,請在SSH客戶端中禁用偽終端分配。 例如,在PuTTY中,它的 連接> SSH> TTY>不分配偽終端 。 然後,轉到 Connection> SSH> Remote命令 並輸入 air ... 命令。 在退出時 檢查 會話>關閉窗口>從不 打開會話。 您應該得到相同的 “未找到空氣” 錯誤。

按優先順序解決此問題的方法:

  1. 修復命令不依賴於特定環境。 在命令中使用完整路徑 air 。 例如:

    /bin/air sandbox run <graph-path>

    如果您不知道完整路徑,則在常見的* nix系統上,您可以在交互式SSH會話中使用 which air 命令。

  2. 修復啟動腳本,以便為交互式和非交互式會話設置相同的 PATH

  3. 嘗試通過登錄shell顯式運行腳本(使用帶有常見* nix shell的 --login 開關):

    bash --login -c "air sandbox run sandbox run <graph-path>"
  4. 如果命令本身依賴於特定的環境設置而無法修復啟動腳本,則可以在命令本身中更改環境。 該語法取決於遠程系統和/或shell。 在常見的* nix系統中,這有效:

    String command="PATH=\"$PATH;/path/to/air\" && air sandbox run <graph-path>";
  5. 另一種(不推薦)方法是使用 .setPty 方法強制“exec”通道的偽終端分配:

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

    使用偽終端自動執行命令可能會帶來令人討厭的副作用。 請參閱示例 是否有一種簡單的方法可以擺脫使用Python的Paramiko庫進行SSH並從遠程計算機的CLI獲取輸出時出現的垃圾值?

對於類似的問題,請參閱

  • 使用JSch通過Java執行某些Unix命令失敗並顯示“... not found”,即使啟用了setPty也是如此
  • 使用JSch執行的命令與SSH終端的行為不同(繞過確認提示消息“是/”否“)
  • JSch:有沒有辦法將用戶環境變量暴露給“exec”通道?
  • 使用SSH.NET SshClient.RunCommand執行的命令(.4gl)失敗並顯示“No such file or directory”

你可以嘗試找出“空氣”所在的位置

whereis air

然後使用這個結果。

就像是

/usr/bin/air sandbox run graph




jsch