1. 參數中的腳本

1. 參數中的腳本

假設我想透過機器A連接到機器B。

ssh -T -J user@machineA user@machineB << END_OF_SSH_CONNECTION
  # Some commands in machine B
END_OF_SSH_CONNECTION

或者

ssh -T user@machineA << END_OF_MACHINE_A
  ssh -T machine B << END_OF_MACHINE_B
    # Some commands in machine B
  END_OF_MACHINE_B
END_OF_MACHINE_A

然而,我不清楚如何啟動一個互動式 shell,使用者可以在連接到機器 B 時鍵入命令。

ssh user@machineA -t 'bash -l -c "bash"'

這也確實有效:

ssh -J user@machineA user@machineB -t 'bash -l -c "bash"'

但是,以下內容不起作用:

ssh -J user@machineA user@machineB -t 'sudo apt-get update; bash -l -c "bash"'
E: Command line option 'l' [from -l] is not understood in combination with the other options.
Connection to machineB closed.

且以下都不是:

ssh -J user@machineA user@machineB -t 'if [ 1 -eq 1 ]; then bash -l -c "bash"; fi'
/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found
Connection to machineB closed.

我也嘗試過這個:

ssh -T -J user@machineA user@machineB << EOF

  # Some commands on machineB

  # Check whether apache2 has been correctly installed
  if [ $(dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -c "ok installed") -eq 1 ];
  then
    printf "done\n";
  else
    printf "fail\nStarting an interactive shell: enter exit to quit\n";
    bash -l -c "bash";
  fi
EOF

最後一個版本幾乎可以工作(即它不回傳任何錯誤),但它不會啟動互動式 shell,使用者可以在其中按我的預期鍵入命令。

我希望有人能夠幫助我。提前致謝。

答案1

感謝您的幫助,@attie。我稍微修改了您建議的程式碼,我在下面報告

#!/usr/bin/env bash

ssh -T -J user@machineA user@machineB 'cat >/tmp/myscript' <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
  echo "done";
else
  echo "fail, starting an interactive shell";
  bash -l -c "bash";
fi
EOF

ssh -t -J user@machineA user@machineB "bash '/tmp/myscript'"

到此,它甚至不需要寫入外部文件。

#!/usr/bin/env bash

ssh -T -J user@machineA user@machineB << "EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q "ok installed"; then
  echo "done";
else
  echo "fail, starting an interactive shell";
  bash -l -c "bash";
fi
EOF

我基本上錯過了周圍的引號EOF,用來避免嘗試擴大領域${Status}

答案2

如果你想在遠端主機上運行腳本獲得一個互動式 shell,那麼你有兩個選擇:

  1. 將整個腳本放入 的命令列參數中ssh
  2. 將腳本推送到遠端主機(例如:使用scpssh),然後執行它(例如:使用ssh

1. 參數中的腳本

你的最後一個例子是在“長的對於這種方法,但是您可以透過使用來幫助提高可讀性mapfile(內建bash)。請注意引用"EOF"以避免嘗試擴展${Status}

mapfile -t SCRIPT <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
  echo "done";
else
  echo "fail, starting an interactive shell";
  bash -l -c "bash";
fi
EOF

ssh -t -J user@machineA user@machineB "${SCRIPT[@]}"

2. 推播腳本,然後執行

使用mktemp後和清理後可獲得獎勵積分。註"EOF"再次引用。

根據您提供的錯誤訊息之一(圍繞exec,請參閱下文以了解更多資訊),這種使用cat >/tmp/myscript可能行不通。

ssh -T -J user@machineA user@machineB 'cat >/tmp/myscript' <<"EOF"
if dpkg-query -W -f='${Status}' apache2 2>/dev/null | grep -q 'ok installed'; then
  echo "done";
else
  echo "fail, starting an interactive shell";
  bash -l -c "bash";
fi
EOF

ssh -t -J user@machineA user@machineB "bash '/tmp/myscript'"

第一步應該始終是嘗試將問題分解為最簡單的形式...關於您的最後一個咒語,請嘗試以下操作:

ssh -T user@machineA << EOF
  bash -l -c "bash";
EOF

會發生什麼事?您將從遠端主機收到任何歡迎訊息,但隨後會話會立即無提示地結束,不會出現錯誤。

改變-T(明確地停用PTY 分配)-t(強制 PTY 分配)提供了正確方向的提示:

ssh -t user@machineA << EOF
  bash -l -c "bash";
EOF
Pseudo-terminal will not be allocated because stdin is not a terminal.

這表示您正在使用stdin提供腳本,然後也嘗試將其stdin(管道,而不是終端)連接到遠端 PTY。

那麼讓我們刪除這個stdin因素:

ssh -t user@machineA bash -l -c "bash"

它有效!

從根本上來說你不能與腳本和終端共享標準輸入。


至於其他錯誤:

E: Command line option 'l' [from -l] is not understood in combination with the other options.

再次,分解它以找到問題。不幸的是,這些命令對我有用,我懷疑是因為我有權訪問的系統正在使用sh -c "${ARGS}"或類似的系統。但是,您提供的另一個錯誤給出了提示:

/usr/local/sbin/start_ttylog.sh: line 67: exec: if: not found

看起來您的系統正在使用exec運行作為ssh...參數給出的命令,這意味著 shell 無法像您希望的那樣處理類似if或為您處理的事情 - 所以路徑上不是二進位並且它失敗。;if

sudo同樣,所有參數都立即給出:

  1. sudo
  2. apt-get
  3. update;
  4. bash
  5. -l
  6. -c
  7. "bash"

果然, (list)sudo參數與(login class)-l是互斥的。-c

相關內容