ssh远程执行多个命令
shell遠程執行:
經常需要遠程到其他節點上執行一些shell命令,如果分別ssh到每臺主機上再去執行很麻煩,因此能有個集中管理的方式就好了。一下介紹兩種shell命令遠程執行的方法。
前提條件:
配置ssh免密碼登陸
對于簡單的命令:
如果是簡單執行幾個命令,則:
ssh user@remoteNode "cd /home ; ls"
基本能完成常用的對于遠程節點的管理了,幾個注意的點:
- 雙引號,必須有。如果不加雙引號,第二個ls命令在本地執行
- 分號,兩個命令之間用分號隔開
對于腳本的方式:
有些遠程執行的命令內容較多,單一命令無法完成,考慮腳本方式實現:
#!/bin/bash ssh user@remoteNode > /dev/null 2>&1 << eeooff cd /home touch abcdefg.txt exit eeooff echo done!
遠程執行的內容在“<< eeooff ” 至“ eeooff ”之間,在遠程機器上的操作就位于其中,注意的點:
- << eeooff,ssh后直到遇到eeooff這樣的內容結束,eeooff可以隨便修改成其他形式。
- 重定向目的在于不顯示遠程的輸出了
- 在結束前,加exit退出遠程節點
http://www.cnblogs.com/ilfmonday/p/ShellRemote.html
目錄?[隱藏]
- 1?SSH命令格式
- 2?主要參數說明
- 3?ssh控制遠程主機,遠程執行命令步驟
- 4?準備工作
- 5?基于公私鑰認證遠程登錄可能存在的不足
- 6?ssh 執行遠程命令格式 - 6.1?打開遠程shell
 
- 7?ssh的-t參數
SSH命令格式
usage: ssh [-1246AaCfgKkMNnqsTtVvXxYy] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-L [bind_address:]port:host:hostport] [-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-p port] [-R [bind_address:]port:host:hostport] [-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] [user@]hostname [command]
主要參數說明
-l 指定登入用戶
 -p 設置端口號
 -f 后臺運行,并推薦加上 -n 參數
 -n 將標準輸入重定向到 /dev/null,防止讀取標準輸入。如果在后臺運行ssh的話(-f選項),就需要這個選項。
 -N 不執行遠程命令,只做端口轉發
 -q 安靜模式,忽略一切對話和錯誤提示
 -T 禁用偽終端配置
 -t (tty)為遠程系統上的ssh進程分配一個偽tty(終端)。如果沒有使用這個選項,當你在遠程系統上運行某條命令的時候,ssh不會為該進程分配tty(終端)。相反,ssh將會把遠端進程的標準輸入和標準輸出附加到ssh會話上去,這通常就是你所希望的(但并非總是如此)。這個選項將強制ssh在遠端系統上分配tty,這樣那些需要tty的程序就能夠正常運行。
 -v verbose)顯示與連接和傳送有關的調試信息。如果命令運行不太正常的話,這個選項就會非常有用。
ssh控制遠程主機,遠程執行命令步驟
第一步,設置ssh免認證,免認證就是不用密碼認證就可以直接登錄,這在寫腳本服務器控制時特別有用。
每二步,就是到遠端服務器上去執行命令
準備工作
基于公私鑰認證(可參考:Linux配置SSH密鑰登錄詳解及客戶端測試使用無密碼登錄)或者用戶名密碼認證(可參考:SSH使用expect自動輸入密碼、命令實現非交互式密碼授權)能確保登錄到遠程服務器
 cmd如果是腳本,注意絕對路徑問題(相對路徑在遠程執行時就是坑)
基于公私鑰認證遠程登錄可能存在的不足
這個可以滿足我們大多數的需求,但是通常運維部署很多東西的時候需要root權限,但是有幾處限制:
 遠程服務器禁止root用戶登錄
 在遠程服務器腳本里轉換身份用expect需要send密碼,這樣不夠安全
ssh 執行遠程命令格式
ssh [options] [user@]host [command]
其中,host為想要連接到的OpenSSH服務器(遠程系統)的名稱,它是惟一的必需參數。host可以是某個本地系統的名稱,也可以是因特網上某個系統的FQDN(參見術語表)或者是一個IP地址。命令ssh host登錄到遠程系統host,使用的用戶名與正在本地系統上使用的用戶名完全相同。如果希望登錄的用戶名與正在本地系統上使用的用戶名不同,那么就應該包含user@。根據服務器設置的不同,可能還需要提供口令。
打開遠程shell
如果沒有提供command參數,ssh就會讓你登錄到host上去。遠程系統顯示一個shell提示符,然后就能夠在host上運行命令。命令exit將會關閉與host的連接,并返回到本地系統的提示符。
例:命令行執行登錄并且在目標服務器上執行命令
ssh user@remoteNode "cd /home ; ls"
基本能完成常用的對于遠程節點的管理了,幾個注意的點:
 如果想在遠程機器上連續執行多條命令,可以用單引號或者雙引號將這些命令括起來。如果不加單引號或者雙引號,第二個ls命令在本地執行。例如 ssh?user@node cd /local ls 則 ls 只會執行 cd /local 命令,ls命令在本地執行,加了雙引號或者單引號,則被括起來的命令被當做ssh命令的一個參數,所以會在遠程連續執行。
 分號,兩個命令之間用分號隔開
例:在目標服務器上執行批量的命令。
#!/bin/bash ssh root@192.168.0.23 < < remotessh killall -9 java cd /data/apache-tomcat-7.0.53/webapps/ exit remotessh
遠程執行的內容在"< < remotessh " 至" remotessh "之間,在遠程機器上的操作就位于其中,注意的點:<< remotessh,ssh后直到遇到remotessh這樣的內容結束,remotessh可以隨便修改成其他形式。在結束前,加exit退出遠程節點 如果不想日志文件在本機出現可以修改配置
ssh root@192.168.0.23 > /dev/null 2>&1 < < remotessh
ssh的-t參數
-t Force pseudo-tty allocation. This can be used to execute arbitrary screen-based programs on a remote machine, which can be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation, even if ssh has no local tty.
中文翻譯一下:就是可以提供一個遠程服務器的虛擬tty終端,加上這個參數我們就可以在遠程服務器的虛擬終端上輸入自己的提權密碼了,非常安全
 命令格式
ssh -t -p $port $user@$ip 'cmd'
示例腳本
#!/bin/bash  #變量定義  
ip_array=("192.168.1.1" "192.168.1.2" "192.168.1.3")  
user="test1"  
remote_cmd="/home/test/1.sh"  #本地通過ssh執行遠程服務器的腳本  
for ip in ${ip_array[*]}  
do  if [ $ip = "192.168.1.1" ]; then  port="7777"  else  port="22"  fi  ssh -t -p $port $user@$ip "remote_cmd"  
done  
 
這個方法還是很方便的,-t虛擬出一個遠程服務器的終端,在多臺服務器同時部署時確實節約了不少時間啊!
例:查看遠程服務器的cpu信息
 假設遠程服務器IP是192.168.110.34
 ssh -l www-online 192.168.110.34 “cat /proc/cpuinfo”
例:執行遠程服務器的sh文件
 首先在遠程服務器的/home/www-online/下創建一個uptimelog.sh腳本
#!/bin/bash uptime >> 'uptime.log' exit 0
使用chmod增加可執行權限
chmod u+x uptimelog.sh
在本地調用遠程的uptimelog.sh
ssh -l www-online 192.168.110.34 "/home/www-online/uptimelog.sh"
執行完成后,在遠程服務器的/home/www-online/中會看到uptime.log文件,顯示uptime內容
www-online@nmgwww34:~$ tail -f uptime.log 21:07:34 up 288 days, 8:07, 1 user, load average: 0.05, 0.19, 0.31
例:執行遠程后臺運行sh
 首先把uptimelog.sh修改一下,修改成循環執行的命令。作用是每一秒把uptime寫入uptime.log
#!/bin/bash while : do uptime >> 'uptime.log' sleep 1 done exit 0
我們需要這個sh在遠程服務器以后臺方式運行,命令如下:
 ssh -l www-online 192.168.110.34 “/home/www-online/uptimelog.sh &”
www-online@onlinedev01:~$ ssh -l www-online 192.168.110.34 "/home/www-online/uptimelog.sh &" www-online@192.168.110.34's password:
輸入密碼后,發現一直停住了,而在遠程服務器可以看到,程序已經以后臺方式運行了。
www-online@nmgwww34:~$ ps aux|grep uptimelog.sh 1007 20791 0.0 0.0 10720 1432 ? S 21:25 0:00 /bin/bash /home/www-online/uptimelog.sh
原因是因為uptimelog.sh一直在運行,并沒有任何返回,因此調用方一直處于等待狀態。
 我們先kill掉遠程服務器的uptimelog.sh進程,然后對應此問題進行解決。
ssh 調用遠程命令后不能自動退出解決方法
 可以將標準輸出與標準錯誤輸出重定向到/dev/null,這樣就不會一直處于等待狀態。
 ssh -l www-online 192.168.110.34 “/home/www-online/uptimelog.sh > /dev/null 2>&1 &”
www-online@onlinedev01:~$ ssh -l www-online 192.168.110.34 "/home/www-online/uptimelog.sh > /dev/null 2>&1 &" www-online@192.168.110.34's password: www-online@onlinedev01:~$
但這個ssh進程會一直運行在后臺,浪費資源,因此我們需要自動清理這些進程。
實際上,想ssh退出,我們可以在ssh執行完成后kill掉ssh這個進程來實現。
 首先,創建一個sh執行ssh的命令,這里需要用到ssh的 -f 與 -n 參數,因為我們需要ssh也以后臺方式運行,這樣才可以獲取到進程號進行kill操作。
 創建ssh_uptimelog.sh,腳本如下
#!/bin/bash  ssh -f -n -l www-online 192.168.110.34 "/home/www-online/uptimelog.sh &" # 后臺運行ssh  pid=$(ps aux | grep "ssh -f -n -l www-online 192.168.110.34 /home/www-online/uptimelog.sh" | awk '{print $2}' | sort -n | head -n 1) # 獲取進程號  echo "ssh command is running, pid:${pid}"  sleep 3 && kill ${pid} && echo "ssh command is complete" # 延遲3秒后執行kill命令,關閉ssh進程,延遲時間可以根據調用的命令不同調整  exit 0   
可以看到,3秒后會自動退出
www-online@onlinedev01:~$ ./ssh_uptimelog.sh www-online@192.168.110.34's password: ssh command is running, pid:10141 ssh command is complete www-online@onlinedev01:~$
然后查看遠程服務器,可以見到uptimelog.sh 在后臺正常執行。
www-online@nmgwww34:~$ ps aux|grep uptime 1007 28061 0.1 0.0 10720 1432 ? S 22:05 0:00 /bin/bash /home/www-online/uptimelog.sh
查看uptime.log,每秒都有uptime數據寫入。
www-online@nmgwww34:~$ tail -f uptime.log 22:05:44 up 288 days, 9:05, 1 user, load average: 0.01, 0.03, 0.08 22:05:45 up 288 days, 9:05, 1 user, load average: 0.01, 0.03, 0.08 22:05:46 up 288 days, 9:05, 1 user, load average: 0.01, 0.03, 0.08 22:05:47 up 288 days, 9:05, 1 user, load average: 0.01, 0.03, 0.08 22:05:48 up 288 days, 9:05, 1 user, load average: 0.01, 0.03, 0.08
附錄:
 1、單引號和雙引號在ssh命令中的區別:
 以一個例子來說明問題,
假設本地機器上配置了JAVA環境變量,在本地執行 echo $JAVA_HOME=/opt/jdk
假若我想查看遠程機器上的JAVA環境變量,則只能使用單引號了,ssh?user@node ‘ echo $JAVA ‘, 則是’ ‘ 中的$JAVA不會被shell解析,而是當做一個字符串,此時參數 echo $JAVA 傳遞給了 ssh;
如果我們使用 ssh?user@node ” echo $JAVA “,則 shell 首先會解析$JAVA,得到它的值,則該命令就變成了 ssh?user@node ‘ echo /opt/jdk ‘ 了
2、可能遇到的問題
 問題:遠程登錄主機時出現Pseudo-terminal will not be allocated because stdin is not a terminal. 錯誤
 解決方案:字面意思是偽終端將無法分配,因為標準輸入不是終端。
所以需要增加-t -t參數來強制偽終端分配,即使標準輸入不是終端。
 to force pseudo-tty allocation even if stdin isn’t a terminal.
參考樣例如下:
 ssh -t -t?user1@host1 -p 9527
參考資料:
 ssh遠程執行命令并自動退出:http://blog.csdn.net/fdipzone/article/details/23000201
http://www.3mu.me/linux%E4%B8%AD%E7%9A%84shell%E7%94%A8ssh%E8%87%AA%E5%8A%A8%E7%99%BB%E5%BD%95%E8%BF%9C%E7%A8%8B%E6%9C%8D%E5%8A%A1%E5%99%A8%E5%90%8E%E6%89%A7%E8%A1%8C%E5%91%BD%E4%BB%A4%E5%B9%B6%E8%87%AA%E5%8A%A8/
總結
以上是生活随笔為你收集整理的ssh远程执行多个命令的全部內容,希望文章能夠幫你解決所遇到的問題。
 
                            
                        - 上一篇: 浅析C语言之uint8_t / uint
- 下一篇: systemd用法
