
假設我想透過機器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,那麼你有兩個選擇:
- 將整個腳本放入 的命令列參數中
ssh
。 - 將腳本推送到遠端主機(例如:使用
scp
或ssh
),然後執行它(例如:使用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
同樣,所有參數都立即給出:
sudo
apt-get
update;
bash
-l
-c
"bash"
果然, (list)sudo
參數與(login class)-l
是互斥的。-c