SSH循環連接

jopen 10年前發布 | 38K 次閱讀 SSH Linux

利用文件描述符做輸入重定向以實現SSH循環連接
先來看一段shell腳本:

theIp="1.1.1.1"
echo $theIp | while read ip; do
    ssh -t root@$ip
done
#
while read ip; do
    ssh -tt root@$ip
done < <(echo $theIp)
#
while true; do
    ssh root@$theIp
    exit
done

經測試發現,只有第三種寫法才可以使用SSH連接,另外兩種都會自動退出

  • 會報錯:tcgetattr: Invalid argument,可以登入遠程機器,但是無法操作,只能通過ctrl+c退出并提示:Killed by signal 2
  • 如果不加參數“-t”,則會提示:Pseudo-terminal will not be allocated because stdin is not a terminal. 然后退出登錄
  • 第二種方式與第一種表現一樣,但是必須加參數“-tt”,用“-t”會自動退出
  • </ul>

    綜上所述,以上前兩種方法完全不科學,用while true只可以登錄一臺,不能連續登錄多臺(雖然幾乎沒有這種需求…)

    于是只好在SF上向高人提問:Why can't ssh connect to any host inside a while loop?

    ssh was eating up your loop's input. Probably in this case your ssh session exits when it gets EOF from it. That's the likely reason but some input may also cause it to exit. You have to redirect its input by specifying < /dev/null or use -n
    <p>@konsolebox回答說,ssh會把循環里的輸入給吃掉!大概就是在獲取了EOF的情況下才導致ssh會話中止。當然也有可能是其他原因。 </p>

    解決方法是把輸入重定向,查看ssh manual:

    -n    Redirects stdin from /dev/null (actually, prevents reading from stdin). This must be used when ssh is run in the background. A common trick is to use this to run X11 programs on a remote machine. For example, ssh -n shadows.cs.hut.fi emacs & will start an emacs on shadows.cs.hut.fi, and the X11 connection will be automatically forwarded over an encrypted channel. The ssh program will be put in the background. (This does not work if ssh needs to ask for a password or passphrase; see also the -f option.)

    將輸入重定向到/dev/null,防止從標準輸入流中讀取數據。ssh在后臺執行的時候必須使用該參數,亦或遠程執行X11程序.

    例如使用-n執行遠程emacs的時候,X11連接會自動轉向一個加密的通道里,并且ssh會被保持在后臺。(如果需要密碼或者密鑰則無效)

    然后他還提出了一個使用文件描述符的完美解決方案來避免ssh讀取標準輸入:

    while read -u 4 ip; do
        ssh root@$ip
        exit
    done 4< <(echo $theIp)

    BASH_BUILTINS中查到,read -u的參數意為:Read lines from file descriptor fd instead of the standard input.

    上面代碼中while read -u 4表示從文件描述符4讀取數據到while循環的ip變量中,然后執行ssh操作,這樣就避免了ssh直接讀取標準輸入,從而可以正常連接遠程主機。

    再來看看“4< <(echo ...)”的寫法(注意中間有空格)。從文件描述符中讀取數據有兩種辦法:

    echo "a b" > test

    創建文件描述符3指向文件test

    exec 3< test

    查看fd3的內容

    cat <&3

    從fd3中讀取數據到變量a和b

    read -u 3 a b echo $a,$b

    使用過程替換將標準輸入轉化為fd4

    exec 4< <(echo "e f")

    一步到位

    read -u5 a b 5< <(echo "ss zz")

    關閉fd3-5

    eval "exec "{3..5}"<&-;"</pre>

sesese色