fabric中文文檔:http://fabric-chs.readthedocs.io/zh_CN/chs/python
視頻教程:http://study.163.com/course/courseMain.htm?courseId=1003852044mysql
安裝: pip3 install fabric3 (注:python3對應要裝fabric3)web
檢查安裝狀況:fab --version正則表達式
進入python3,sql
>>> import fabricshell
>>> dir(fabric)apache
新建目錄: cd /usr/local/fabricwindows
命令行命令:centos
fab -u 用戶名 -p 密碼 -H ‘10.0.0.202’ -- ‘netstat -anptu | grep 22'api
fab -u 用戶名 -p 密碼 -H '10.0.0.202,10.0.0.203,10.0.0.204' -- 'uname-a'
fab -u 用戶名 -p 密碼 -H '10.0.0.203,10.0.0.204' -- 'yum clean all & yum repolist all'
fab -u 用戶名 -p 密碼 -H '10.0.0.203.10.0.0.204' -P(並行) --'reboot'
fab -u 用戶名 -p 密碼 -H '10.0.0.203,10.0.0.204' -P --'yum clean all & yum repolist all'
fab -u 用戶名 -p 密碼 -H '10.0.0.203,10.0.0.204' -- 'system stop firewalld.service'
fab -u 用戶名 -p 密碼 -H '10.0.0.202,10.0.0.203,10.0.0.204' -P -- 'yum -y install gpm* && service gpm start &&systemctl enable gpm.service'
fab -u用戶名 -p 密碼 -H '10.0.0.204' -- 'yum -y install httpd && systemctl start httpd.service && systemctl enable httpd.service'
瀏覽器輸入10.0.0.204,能夠進入apache界面,爲安裝正常
fab -u用戶名 -p 密碼 -H '10.0.0.204' -- 'netstat -anptu | grep 80'
備註:CentOS7服務使用方法
服務使用方法
systemctl start [服務文件名]
systemctl restart [服務文件名]
systemctl stop [服務文件名]
systemctl status [服務文件名]
設置開機啓動
systemctl enable [服務文件名]
systemctl disable [服務文件名]
fabfile文件:
env.hosts = ['10.0.0.203','10.0.0.204'] 定義Ip或主機名列表
env.user = 'root' 定義用戶名
env.port = 22 定義端口
env.password = '密碼' 定義密碼
env.password={'root@10.0.0.203:22':"密碼",
'root@10.0.0.204:22':「密碼」} 定義用戶名、ip、端口、密碼
env.gateway = '10.0.0.254' 定義網關
env.roledefs = {"webservice":["10.0.0.203","10.0.0.204"],
"dbservice":["10.0.0.210","10.0.0.211"] 定義角色分租
函數 定義:
from fabric.api import * local #執行本地命令,如local('uname -s') lcd #切換本地目錄,如lcd('/home') cd #切換遠程目錄,如cd('/var/logs') run #執行遠程命令,如run('free -m') sudo #sudo方式執行遠程命令,如sudo('/etc/init.d/httpd start') put #上次本地文件導遠程主機,如put('/home/user.info','/data/user.info') get #從遠程主機下載文件到本地,如:get('/data/user.info','/home/user.info') prompt #得到用戶輸入信息,如:prompt('please input user password:') confirm #得到提示信息確認,如:confirm('Test failed,Continue[Y/N]?') reboot #重啓遠程主機,如:reboot() @task #函數修飾符,標識的函數爲fab可調用的,非標記對fab不可見,純業務邏輯 @runs_once #函數修飾符,標識的函數只會執行一次,不受多臺主機影響 @roles() #運行指定的角色組裏,經過env.roledefs裏的定義 from fabric.colors import * print blue(text) print cyan(text) print green(text) print magenta(text) print red(text) print white(text) print yellow(text)
新建文件: vi fabfile.py (fab自動調用文檔,其定義的每個函數,就是一個命令)
fabfile.py中可寫入文檔以下:
from fabric.api import *
def host_type():
run('uname -s')
run('hostname')
fab -H localhost host_tpye (-H localhost指定本機運行)
env.hosts=[
'root@10.0.0.2:22',
'root@10.0.0.3:22']
env.password = '密碼'
def host_type():
run('uname -s')
fab host_typt
新建文件 c.py
from fabric.api import * env.hosts = ["10.0.0.203","10.0.0.204"] env.passwords = { 'root@10.0.0.203:22':'z', 'root@10.0.0.204:22':'z'} env.roledefs = { 'webserver':['10.0.0.204'], 'dbserver':['10.0.0.203']} @task def show(): run("hostname") #run("netstat -anput | grep 22") #run("ls /root/") @task @roles('webserver') def install_httpd(): print('install webserver') @task @roles('dbserver') def install_mysql(): print('install_mysql') @task def run_all(): execute(show) execute(install_httpd) execute(install_mysql)
if __name__ == '__main__': execute(run_all)
fab -f c.py -l
fab -f c.py show
fab -f c.py run_all
python3 c.pu (對應文中if判斷)
新建文件 d.py
from fabric.api import * from fabric.colors import * env.hosts = ["10.0.0.203","10.0.0.204"] env.passwords = { 'root@10.0.0.203:22':'z', 'root@10.0.0.204:22':'z'} env.roledefs = { 'webserver':['10.0.0.204'], 'dbserver':['10.0.0.203']} @task def local_cmd(): local('ls -la') with lcd('/usr/local'): local("ls -la") @task def runsudo1(): run('free -m') sudo('cat /etc/passwd') @task def cd1(): with cd('/etc'): run('ls -la') @task def put1(): put('d.py','/usr/local/') run('ls -la /usr/local/') @task def get1(): get('/usr/local/d.py','dd.py') local('ls -la') @task def prompt1(): content1 = prompt("請輸入字符:") print(content1) @task def color1(): print(white('hello world!')) print(yellow('hello world!')) print(red('hello world!')) print(blue('hello world!')) print(green('hello world!')) print(cyan('hello world!')) print(magenta('hello world!'))
confirm
(env1) [root@centos7-3 env1]# python3 >>> from fabric.contrib.console import confirm >>> content = confirm('continue[Y/N]?') continue[Y/N]? [Y/n] y >>> content True >>> content = confirm('continue[Y/N]?') continue[Y/N]? [Y/n] n >>> content False
文件的打包 、上傳、校驗、下載:
打包:tar -czf xxx.tar.gz.xxx
解包:tar -zxf xxx.tar.gz -C 路徑
上傳:put('本地文件路徑',‘遠程文件路徑’)
下載:get(‘遠程文件路徑’,‘本地文件路徑’)
新建文件 e.py
1 from fabric.api import* 2 from fabric.contrib.console import confirm 3 from fabric.colors import * 4 5 env.hosts =['10.0.0.204'] 6 env.user = 'root' 7 8 env.passwords = { 9 'root@10.0.0.203:22':'z', 10 'root@10.0.0.204:22':'z'} 11 12 @task 13 def upload_file(): 14 with settings(warn_only=True): 15 local('tar -czf b.tar.gz b.py') 16 result = put('b.tar.gz','/usr/local/') 17 if result.failed and not confirm('continue[Y/N]?'): 18 abort('put b.tar.gz failed!') 19 with settings(warn_only=True): 20 local_file = local('md5sum b.tar.gz',capture=True).split(" ")[0] 21 remote_file = run('md5sum /usr/local/b.tar.gz').split(" ")[0] 22 if local_file == remote_file: 23 print(green('local == remote')) 24 else: 25 print(red('local != remote')) 26 run('mkdir /usr/local/test') 27 run('tar -zxf /usr/local/b.tar.gz -C /usr/local/test/') 28 29 @task 30 def download_file(): 31 with settings(warn_only=True): 32 get('/usr/local/b.tar.gz','/usr/local/b1.tar.gz') 33 local('mkdir /usr/local/test1') 34 local('tar -zxf /usr/local/b1.tar.gz -C /usr/local/test1')
多主機並行運維:
新建文件夾 f.py
@parallel #並行
from fabric.api import * env.user = "root" host1 = "10.0.0.202" host2 = "10.0.0.203" host3 = "10.0.0.204" env.hosts = [host1,host2,host3] env.passwords ={ "root@10.0.0.202:22":"z", "root@10.0.0.203:22":"z", "root@10.0.0.204:22":"z"} @task @parallel @hosts(host1,host2,host3) def install_ftp(): run("yum clean all") run("yum repolist all") run("yum -y install vsftpd") run("systemctl start vsftpd.service") run("systemctl enable vsftpd.service") run("systemctl status vsftpd.service")
如下文檔轉載自:http://blog.51cto.com/lizhenliang/1880856
本章節主要講解運維工程師比較感興趣的知識,那就是運維批量管理,在Python下有paramiko、fabric和pexpect這三個模塊可幫助運維實現自動化部署、批量執行命令、文件傳輸等常規任務,接下來一塊兒看看它們的使用方法吧!
18.1 paramiko
paramiko模塊是基於Python實現的SSH遠程安全鏈接,用於SSH遠程執行命令、文件傳輸等功能。
默認Python沒有,須要手動安裝:pip install paramiko
如安裝失敗,能夠嘗試yum安裝:yum install python-paramiko
18.1.1 SSH密碼認證遠程執行命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
#!/usr/bin/python
# -*- coding: utf-8 -*-
import
paramiko
import
sys
hostname
=
'192.168.1.215'
port
=
22
username
=
'root'
password
=
'123456'
client
=
paramiko.SSHClient()
# 綁定實例
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname, port, username, password, timeout
=
5
)
stdin, stdout, stderr
=
client.exec_command(
'df -h'
)
# 執行bash命令
result
=
stdout.read()
error
=
stderr.read()
# 判斷stderr輸出是否爲空,爲空則打印執行結果,不爲空打印報錯信息
if
not
error:
print
result
else
:
print
error
client.close()
|
18.1.2 私鑰認證遠程執行命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
#!/usr/bin/python
# -*- coding: utf-8 -*-
import
paramiko
import
sys
hostname
=
'192.168.1.215'
port
=
22
username
=
'root'
key_file
=
'/root/.ssh/id_rsa'
cmd
=
" "
.join(sys.argv[
1
:])
def
ssh_conn(command):
client
=
paramiko.SSHClient()
key
=
paramiko.RSAKey.from_private_key_file(key_file)
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(hostname, port, username, pkey
=
key)
stdin, stdout, stderr
=
client.exec_command(command)
# 標準輸入,標準輸出,錯誤輸出
result
=
stdout.read()
error
=
stderr.read()
if
not
error:
print
result
else
:
print
error
client.close()
if
__name__
=
=
"__main__"
:
ssh_conn(cmd)
|
18.1.3 上傳文件到遠程服務器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#!/usr/bin/python
# -*- coding: utf-8 -*-
import
os, sys
import
paramiko
hostname
=
'192.168.1.215'
port
=
22
username
=
'root'
password
=
'123456'
local_path
=
'/root/test.txt'
remote_path
=
'/opt/test.txt'
if
not
os.path.isfile(local_path):
print
local_path
+
" file not exist!"
sys.exit(
1
)
try
:
s
=
paramiko.Transport((hostname, port))
s.connect(username
=
username, password
=
password)
except
Exception as e:
print
e
sys.exit(
1
)
sftp
=
paramiko.SFTPClient.from_transport(s)
# 使用put()方法把本地文件上傳到遠程服務器
sftp.put(local_path, remote_path)
# 簡單測試是否上傳成功
try
:
# 若是遠程主機有這個文件則返回一個對象,不然拋出異常
sftp.
file
(remote_path)
print
"上傳成功."
except
IOError:
print
"上傳失敗!"
finally
:
s.close()
|
18.1.4 從遠程服務器下載文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
#!/usr/bin/python
# -*- coding: utf-8 -*-
import
os, sys
import
paramiko
hostname
=
'192.168.1.215'
port
=
22
username
=
'root'
password
=
'123456'
local_path
=
'/root/test.txt'
remote_path
=
'/opt/test.txt'
try
:
s
=
paramiko.Transport((hostname, port))
s.connect(username
=
username, password
=
password)
sftp
=
paramiko.SFTPClient.from_transport(s)
except
Exception as e:
print
e
sys.exit(
1
)
try
:
# 判斷遠程服務器是否有這個文件
sftp.
file
(remote_path)
# 使用get()方法從遠程服務器拉去文件
sftp.get(remote_path, local_path)
except
IOError as e:
print
remote_path
+
"remote file not exist!"
sys.exit(
1
)
finally
:
s.close()
# 測試是否下載成功
if
os.path.isfile(local_path):
print
"下載成功."
else
:
print
"下載失敗!"
|
18.1.5 上傳目錄到遠程服務器
paramiko模塊並無實現直接上傳目錄的類,已經知道了如何上傳文件,再寫一個上傳目錄的代碼就簡單了,利用os庫的os.walk()方法遍歷目錄,再一個個上傳:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
|
#!/usr/bin/python
# -*- coding: utf-8 -*-
import
os, sys
import
paramiko
hostname
=
'192.168.1.215'
port
=
22
username
=
'root'
password
=
'123456'
local_path
=
'/root/abc'
remote_path
=
'/opt/abc'
# 去除路徑後面正斜槓
if
local_path[
-
1
]
=
=
'/'
:
local_path
=
local_path[
0
:
-
1
]
if
remote_path[
-
1
]
=
=
'/'
:
remote_path
=
remote_path[
0
:
-
1
]
file_list
=
[]
if
os.path.isdir(local_path):
for
root, dirs, files
in
os.walk(local_path):
for
file
in
files:
# 獲取文件絕對路徑
file_path
=
os.path.join(root,
file
)
file_list.append(file_path)
else
:
print
path
+
"Directory not exist!"
sys.exit(
1
)
try
:
s
=
paramiko.Transport((hostname, port))
s.connect(username
=
username, password
=
password)
sftp
=
paramiko.SFTPClient.from_transport(s)
except
Exception as e:
print
e
for
local_file
in
file_list:
# 替換目標目錄
remote_file
=
local_file.replace(local_path, remote_path)
remote_dir
=
os.path.dirname(remote_file)
# 若是遠程服務器沒目標目錄則建立
try
:
sftp.stat(remote_dir)
except
IOError:
sftp.mkdir(remote_dir)
print
"%s -> %s"
%
(local_file, remote_file)
sftp.put(local_file, remote_file)
s.close()
|
sftp是安全文件傳輸協議,提供一種安全的加密方法,sftp是SSH的一部分,SFTPClient類實現了sftp客戶端,經過已創建的SSH通道傳輸文件,與其餘的操做,以下:
sftp.getcwd() | 返回當前工做目錄 |
sftp.chdir(path) | 改變工做目錄 |
sftp.chmod(path, mode) | 修改權限 |
sftp.chown(path, uid, gid) | 設置屬主屬組 |
sftp.close() | 關閉sftp |
sftp.file(filename, mode='r', bufsize=-1) | 讀取文件 |
sftp.from_transport(s) | 建立SFTP客戶端通道 |
sftp.listdir(path='.') | 列出目錄,返回一個列表 |
sftp.listdir_attr(path='.') | 列出目錄,返回一個SFTPAttributes列表 |
sftp.mkdir(path, mode=511) | 建立目錄 |
sftp.normalize(path) | 返回規範化path |
sftp.open(filename, mode='r', bufsize=-1) | 在遠程服務器打開文件 |
sftp.put(localpath, remotepath, callback=None) | localpath文件上傳到遠程服務器remotepath |
sftp.get(remotepath, localpath, callback=None) | 從遠程服務器remotepath拉文件到本地localpath |
sftp.readlink(path) | 返回一個符號連接目標 |
sftp.remove(path) | 刪除文件 |
sftp.rename(oldpath, newpath) | 重命名文件或目錄 |
sftp.rmdir(path) | 刪除目錄 |
sftp.stat(path) | 返回遠程服務器文件信息(返回一個對象的屬性) |
sftp.truncate(path, size) | 截取文件大小 |
sftp.symlink(source, dest) | 建立一個軟連接(快捷方式) |
sftp.unlink(path) | 刪除軟連接 |
博客地址:http://lizhenliang.blog.51cto.com
QQ羣:323779636(Shell/Python運維開發羣)
18.2 fabric
fabric模塊是在paramiko基礎上又作了一層封裝,操做起來更方便。主要用於多臺主機批量執行任務。
默認Python沒有,須要手動安裝:pip install fabric
如安裝失敗,能夠嘗試yum安裝:yum install fabric
Fabric經常使用API:
API類 |
描述 |
示例 |
local | 執行本地命令 | local('uname -s') |
lcd | 切換本地目錄 | lcd('/opt') |
run | 執行遠程命令 | run('uname -s') |
cd | 切換遠程目錄 | cd('/opt') |
sudo | sudo方式執行遠程命令 | sudo('/etc/init.d/httpd start') |
put | 上傳本地文件或目錄到遠程主機 | put(remote_path, local_path) |
get | 從遠程主機下載文件或目錄到本地 | put(local_path, remote_path) |
open_shell | 打開一個shell,相似於SSH鏈接到了遠程主機 | open_shell("ifconfig eth0") |
prompt | 得到用戶輸入信息 | prompt('Please input user password: ') |
confirm | 得到提示信息確認 | confirm('Continue[Y/N]?') |
reboot | 重啓遠程主機 | reboot() |
@task | 函數裝飾器,引用說明函數可調用,不然不可見 | |
@runs_once | 函數裝飾器,函數只會執行一次 |
當咱們寫好fabric腳本後,須要用fab命令調用執行任務。
命令格式:fab [options] <command>[:arg1,arg2=val2,host=foo,hosts='h1;h2',...] ...
fab命令有如下經常使用選項:
選項 |
描述 |
-l | 打印可用的命令(函數) |
--set=KEY=VALUE,... | 逗號分隔,設置環境變量 |
--shortlist | 簡短打印可用命令 |
-c PATH | 指定本地配置文件 |
-D | 不加載用戶known_hosts文件 |
-f PATH | 指定fabfile文件 |
-g HOST | 逗號分隔要操做的主機 |
-i PATH | 指定私鑰文件 |
-k | 不加載來自~/.ssh下的私鑰文件 |
-p PASSWORD | 使用密碼認證and/or sudo |
-P | 默認爲並行執行方法 |
--port=PORT | 指定SSH鏈接端口 |
-R ROLES | 根據角色操做,逗號分隔 |
-s SHELL | 指定新shell,默認是'/bin/bash -l -c' |
--show=LEVELS | 以逗號分隔的輸出 |
--ssh-config-path=PATH | SSH配置文件路徑 |
-t N | 設置鏈接超時時間,單位秒 |
-T N | 設置遠程命令超時時間,單位秒 |
-u USER | 鏈接遠程主機用戶名 |
-x HOSTS | 以逗號分隔排除主機 |
-z INT | 併發進程數 |
18.2.1 本地執行命令
1
2
3
4
5
6
7
|
from
fabric.api
import
local
def
command():
local(
'ls'
)
# fab command
[localhost] local: ls
fabfile.py fabfile.pyc tab.py tab.pyc
Done.
|
使用fab命令調用,默認尋找當前目錄的fabfile.py文件。
18.2.2 遠程執行命令
1
2
3
4
5
6
7
8
9
10
11
12
|
from
fabric.api
import
run
def
command():
run(
'ls'
)
# fab -H 192.168.1.120 -u user command
[
192.168
.
1.120
] Executing task
'command'
[
192.168
.
1.120
] run: ls
[
192.168
.
1.120
] Login password
for
'user'
:
[
192.168
.
1.120
] out: access.log a.py
[
192.168
.
1.120
] out:
Done.
Disconnecting
from
192.168
.
1.120
... done.
|
若是在多臺主機執行,只須要-H後面的IP以逗號分隔便可。
18.2.3 給腳本函數傳入位置參數
1
2
3
4
5
6
7
8
9
10
11
|
from
fabric.api
import
run
def
hello(name
=
"world"
):
print
(
"Hello %s!"
%
name)
# fab -H localhost hello
[localhost] Executing task
'hello'
Hello world!
Done.
# fab -H localhost hello:name=Python
[localhost] Executing task
'hello'
Hello Python!
Done.
|
18.2.4 主機列表組
1
2
3
4
5
6
|
from
fabric.api
import
run, env
env.hosts
=
[
'root@192.168.1.120:22'
,
'root@192.168.1.130:22'
]
env.password
=
'123.com'
env.exclude_hosts
=
[
'root@192.168.1.120:22'
]
# 排除主機
def
command():
run(
'ls'
)
|
env做用是定義fabfile全局設定,相似於變量。還有一些經常使用的屬性:
env屬性 |
描述 |
示例 |
env.hosts | 定義目標主機 | env.hosts = ['192.168.1.120:22'] |
env.exclude_hosts | 排除指定主機 | env.exclude_hosts = '[192.168.1.1]' |
env.user | 定義用戶名 | env.user='root' |
env.port | 定義端口 | env.port='22' |
env.password | 定義密碼 | env.password='123' |
env.passwords | 定義多個密碼,不一樣主機對應不一樣密碼 | env.passwords = {'root@192.168.1.120:22': '123'} |
env.gateway | 定義網關 | env.gateway='192.168.1.2' |
env.roledefs | 定義角色分組 | env.roledef = {'web':['192.168.1.11'], 'db':['192.168.1.12']} |
env.deploy_release_dir | 自定義全局變量,格式:env.+ '變量名' | env.var |
18.2.5 定義角色分組
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# vi install.py
from
fabric.api
import
run, env
env.roledefs
=
{
'web'
: [
'192.168.1.10'
,
'192.168.1.20'
],
'db'
: [
'192.168.1.30'
,
'192.168.1.40'
]
}
env.password
=
'123'
@roles
(
'web'
)
def
task1():
run(
'yum install httpd -y'
)
@roles
(
'db'
)
def
task2():
run(
'yum install mysql-server -y'
)
def
deploy():
execute(task1)
execute(task2)
# fab -f install.py deploy
|
18.2.6 上傳目錄到遠程主機
1
2
3
4
5
6
7
8
|
from
fabric.api
import
*
env.hosts
=
[
'192.168.1.120'
]
env.user
=
'user'
env.password
=
'123.com'
def
task():
put(
'/root/abc'
,
'/home/user'
)
run(
'ls -l /home/user'
)
# fab task
|
18.2.7 從遠程主機下載目錄
1
2
3
4
5
6
7
8
|
from
fabric.api
import
*
env.hosts
=
[
'192.168.1.120'
]
env.user
=
'user'
env.password
=
'123.com'
def
task():
get(
'/home/user/b'
,
'/opt'
)
local(
'ls -l /opt'
)
# fab task
|
18.2.8 打印顏色,有助於關鍵地方醒目
1
2
3
4
5
6
|
from
fabric.colors
import
*
def
show():
print
green(
'Successful.'
)
print
red(
'Failure!'
)
print
yellow(
'Warning.'
)
# fab show
|
通過上面演示fabric主要相關功能,是否是以爲很適合批量自動部署呢!沒錯,經過編寫簡單的腳本,便可完成複雜的操做。
博客地址:http://lizhenliang.blog.51cto.com
QQ羣:323779636(Shell/Python運維開發羣)
18.3 pexpect
pexpect是一個用來啓動子程序,並使用正則表達式對程序輸出作出特定響應,以此實現與其自動交互的Python模塊。暫不支持Windows下的Python環境執行。
這裏主要講解run()函數和spawn()類,能完成自動交互,下面簡單瞭解下它們使用。
18.3.1 run()
run()函數用來運行bash命令,相似於os模塊中的system()函數。
參數:run(command, timeout=-1, withexitstatus=False, events=None, extra_args=None, logfile=None, cwd=None, env=None)
1
2
3
4
5
|
例
1
:執行ls命令
>>>
import
pexpect
>>> pexpect.run(
"ls"
)
例
2
:得到命令狀態返回值
>>> command_output, exitstatus
=
pexpect.run(
"ls"
, withexitstatus
=
1
)
|
command_outout是執行結果,exitstatus是退出狀態值。
18.3.2 spawn()
spawn()是pexpect模塊主要的類,實現啓動子程序,使用pty.fork()生成子進程,並調用exec()系列函數執行命令。
參數:spawn(command, args=[], timeout=30, maxread=2000, searchwindowsize=None, logfile=None, cwd=None, env=None)
spawn()類幾個經常使用函數:
expect(pattern, timeout=-1, searchwindowsize=None) | 匹配正則表達式,pattern能夠是正則表達式。 |
send(s) | 給子進程發送一個字符串 |
sendline(s='') | 就像send(),但添加了一個換行符(os.lineseq) |
sendcontrol(char) | 發送一個控制符,好比ctrl-c、ctrl-d |
例子:ftp交互
用ftp命令登陸是這樣的,須要手動輸入用戶名和密碼,才能登陸進去。
1
2
3
4
5
6
7
8
9
10
11
|
# ftp 192.168.1.10
Connected to
192.168
.
1.10
(
192.168
.
1.10
).
220
-
FileZilla Server version
0.9
.
46
beta
220
-
written by Tim Kosse (tim.kosse@filezilla
-
project.org)
220
Please visit http:
/
/
sourceforge.net
/
projects
/
filezilla
/
Name (
192.168
.
1.10
:root): yunwei
331
Password required
for
yunwei
Password:
230
Logged on
Remote system
type
is
UNIX.
ftp>
|
下面咱們用pexpect幫咱們完成輸入用戶名和密碼:
1
2
3
4
5
6
7
8
9
10
11
|
import
pexpect
child
=
pexpect.spawn(
'ftp 192.168.1.10'
)
child.expect(
'Name .*: '
)
child.sendline(
'yunwei'
)
child.expect(
'Password:'
)
child.sendline(
'yunweipass'
)
child.expect(
'ftp> '
)
child.sendline(
'ls'
)
child.sendline(
'bye'
)
child.expect(pexpect.EOF)
# pexpect.EOF程序打印提示信息
print
child.before
# 保存命令執行結果
|
手動輸入時,是來自鍵盤的標準輸入,而pexpect是先匹配到關鍵字,再向子進程發送字符串。
pexpect.EOF打印提示信息,child.before保存的是命令執行結果。
經過上面的例子想必你已經知道pexpect主要功能了,在交互場景下頗有用,這裏就講解這麼多了,目的是給你們提供一個自動交互實現思路。
小結:
經過對Python下paramiko、fabric和pexpect模塊使用,它們各有本身擅長的一面。
paramiko:方便嵌套系統平臺中,擅長遠程執行命令,文件傳輸。
fabric:方便與shell腳本結合,擅長批量部署,任務管理。
pexpect:擅長自動交互,好比ssh、ftp、telnet。