Linux Shell遠程執行命令(命令行與腳本方式)


shell遠程執行:

  經常需要遠程到其他節點上執行一些shell命令,如果分別ssh到每台主機上再去執行很麻煩,因此能有個集中管理的方式就好了。一下介紹兩種shell命令遠程執行的方法。

前提條件:

  配置ssh免密碼登陸

對於簡單的命令:

  如果是簡單執行幾個命令,則:

ssh user@remoteNode "cd /home ; ls"

  基本能完成常用的對於遠程節點的管理了,幾個注意的點:

  1. 雙引號,必須有。如果不加雙引號,第二個ls命令在本地執行
  2. 分號,兩個命令之間用分號隔開

對於腳本的方式:

  有些遠程執行的命令內容較多,單一命令無法完成,考慮腳本方式實現:

#!/bin/bash
ssh user@remoteNode > /dev/null 2>&1 << eeooff
cd /home
touch abcdefg.txt
exit
eeooff
echo done!

遠程執行的內容在“<< eeooff ” 至“ eeooff ”之間,在遠程機器上的操作就位於其中,注意的點:

  1. << eeooff,ssh后直到遇到eeooff這樣的內容結束,eeooff可以隨便修改成其他形式。
  2. 重定向目的在於不顯示遠程的輸出了
  3. 在結束前,加exit退出遠程節點

http://www.cnblogs.com/ilfmonday/p/ShellRemote.html

目錄 [隱藏]

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/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM