返回顶部
首页 > 资讯 > 后端开发 > Python >Python批量管理主机(paramik
  • 451
分享到

Python批量管理主机(paramik

批量主机Python 2023-01-31 02:01:53 451人浏览 薄情痞子

Python 官方文档:入门教程 => 点击学习

摘要

paramikoparamiko模块是基于python实现的ssh远程安全连接,用于SSH远程执行命令、文件传输等功能。默认Python没有,需要手动安装:pip install paramiko如安装失败,可以尝试yum安装:yum in

paramiko

paramiko模块是基于python实现的ssh远程安全连接,用于SSH远程执行命令、文件传输等功能。


默认Python没有,需要手动安装:pip install paramiko


如安装失败,可以尝试yum安装:yum install python-paramiko



基于账号密码的形式,执行命令或上传下载文件

import paramiko
 
# 基于账号密码执行命令
# 创建SSH对象
ssh = paramiko.SSHClient()
# 允许连接不在know_hosts文件中的机器
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
# 连接服务器
ssh.connect(hostname="192.168.80.20", port=22, username="root", passWord="test@2015")
# 执行命令
stdin, stdout, stderr = ssh.exec_command("free -m")
# 获取命令结果
res, err = stdout.read(), stderr.read()
result = res if res else err
print(result.decode())
# 关闭连接
ssh.close()
 
# 基于账号密码的上传下载
transport = paramiko.Transport(("192.168.80.20", 22))
transport.connect(username="root", password="test@2015")
sftp = paramiko.SFTPClient.from_transport(transport)
# 将location.py上传至服务器的/tmp/test.py
sftp.put("高级FTP.png", "/root/高级FTP.png")
# 将remove_path下载到本地local_path
sftp.get("remove_path", "local_path")
transport.close()
 
# SSHClient 封装 Transport
transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', password='123')
ssh = paramiko.SSHClient()
ssh._transport = transport
stdin, stdout, stderr = ssh.exec_command('df')
print(stdout.read().decode())
transport.close()






基于密钥的形式,执行命令或上传下载文件




import paramiko
 
# 基于密钥执行命令
private_key = paramiko.RSAKey.from_private_key_file("id_rsa")
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname="192.168.80.24", port=22, username="root", pkey=private_key)
stdin, stdout, stderr = ssh.exec_command("ifconfig")
res, err = stdout.read(), stderr.read()
result = res if res else err
print(result.decode())
ssh.close()
 
# 基于密钥的上传下载
private_key = paramiko.RSAKey.from_private_key_file("id_rsa")
transport = paramiko.Transport(("192.168.80.24", 22))
transport.connect(username="root", pkey=private_key)
sftp = paramiko.SFTPClient.from_transport(transport)
sftp.get("test.txt", "1")
transport.close()
 
# SSHClient 封装 Transport
private_key = paramiko.RSAKey.from_private_key_file('/home/auto/.ssh/id_rsa')
transport = paramiko.Transport(('hostname', 22))
transport.connect(username='wupeiqi', pkey=private_key)
ssh = paramiko.SSHClient()
ssh._transport = transport
stdin, stdout, stderr = ssh.exec_command('df')
transport.close()


SSH密码认证远程执行命令



#!/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()


私钥认证远程执行命令


#!/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)


上传文件到远程服务器


#!/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()


从远程服务器下载文件


#!/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 "下载失败!"



上传目录到远程服务器

paramiko模块并没有实现直接上传目录的类,已经知道了如何上传文件,再写一个上传目录的代码就简单了,利用os库的os.walk()方法遍历目录,再一个个上传:

#!/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()


传输文件


#!/usr/bin/python

#-*- coding:UTF-8 -*-


try:

    import os,sys

    import re

    import datetime

    import shutil

    import commands


    from optparse import OptionParser

except ImportError,e:

    print "Error:",e

    sys.exit()


def Get_And_ScpLogfile(host,list,tmpdir,yestoday):

    logdir = '/log/'

    desdir = '/home/haoren/logdir/'

    global dirs;dirs = []

    for ip in list:

        ident = ip.split('.')[3]

        ldir = '%s%s_%s' % (tmpdir,yestoday,ident)

        dirs.append(ldir) 

        if not os.path.exists(ldir):

                os.makedirs(ldir)


        s,o = commands.getstatusoutput('ssh %s /bin/ls -ld %s%s ' % (ip,logdir,yestoday))

        print "********************************************%s**************************************************" % ip

        print "BEGIN:"

        if s == 0:

            os.system('/usr/bin/scp -r %s:%s%s/* %s' % (ip,logdir,yestoday,ldir)) 

        else:

            os.system('/usr/bin/scp -r %s:%s*%s* %s' % (ip,logdir,yestoday,ldir)) 



    for ip in host:

         print "**************************************SCP_To_%s**************************************************" % ip

         print "BEGIN:"

         os.system('/usr/bin/scp -r %s%s* %s:%s' % (tmpdir,yestoday,ip,desdir))     


def CleanLogFile():

    for d in dirs:

        shutil.rmtree(d,True)


def main():

    ####option####

    parser = OptionParser()

    parser.add_option("-t","--time",action="store",dest="filedate",help="appoint the logfile time,use like this '-t 130825'")

    (options,args) = parser.parse_args()


    ####option####

    

    if options.filedate:

        filedate = options.filedate

    else:

        filedate = (datetime.datetime.now() - datetime.timedelta(days=1)).strftime('%y%m%d')


    iplist = []

    host = []

    tmpdir = '/home/haoren/tempdir/'

    f = open('/home/haoren/tools/log_config.ini','r')

    for line in f:

        line = line.strip()

        if re.search(r'^[0-9]{1,2}=.*',line):

            iplist.append(line.split('=')[1])

        elif re.search(r'^host=.*',line):

            #host = line.split('=')[1]

            host.append(line.split('=')[1])

        elif re.search(r'^host2=.*',line):

        #    host2 = line.split('=')[1]

            host.append(line.split('=')[1])

    f.close()

    Get_And_ScpLogfile(host,iplist,tmpdir,filedate) 

    CleanLogFile()


if __name__ == "__main__":

    main()


shutil 用来处理 文件 文件夹 压缩包 的模块


import shutil

  

# 拷贝文件内容

shutil.copyfileobj(open('old.xml', 'r'), open('new.xml', 'w'))

  

# 拷贝文件

shutil.copyfile('f1.log', 'f2.log')

  

# 拷贝权限

shutil.copymode('f1.log', 'f2.log')

  

# 拷贝文件状态信息

shutil.copystat('f1.log', 'f2.log')

  

# 拷贝文件和权限

shutil.copy('f1.log', 'f2.log')

  

# 递归地拷贝文件夹

# shutil.copytree('folder1', 'folder2',

ignore=shutil.ignore_patterns('*.pyc', '*.txt'))

  

# 递归地删除文件

# shutil.rmtree('folder2')

  

# 递归地移动重命名文件

# shutil.move('folder2', 'folder3')

  

# 打包文件

ret = shutil.make_arcHive(r'C:\GitHub\Python\day7\shutil\www', 'gztar',

root_dir=r'C:\gitHub\Python\day7\shutil\folder1') 



zipfile tarfile


import zipfile

  

# 压缩

z = zipfile.ZipFile('z.zip', 'w')

z.write('xo.xml')

z.write('xxxoo.xml')

z.close()

  

# 解压

z = zipfile.ZipFile('z.zip', 'r')

for item in z.namelist():

    print(item)

# z.extractall()

z.extract('xo.xml')

  

import tarfile

  

# 压缩

tar = tarfile.open('z.tar', 'w')

tar.add('xo.xml', arcname='bbs2.log')

tar.add('xxxoo.xml', arcname='cmdb.log')

tar.close()

  

# 解压

tar = tarfile.open('z.tar', 'r')

# for item in tar.getmembers():

#     print(item, type(item))

obj = tar.getmember('cmdb.log')  # 和zipfile不同的是 再解压特定文件前要先获取文件特殊对象值

tar.extract(obj)

tar.close()




和处理shell相关的命令


import subprocess

  

# 返回命令执行结果

# result = subprocess.call('ls -l', shell=True)

# result = subprocess.call(['ls', '-l'], shell=False)

# print(result)

  

# subprocess.check_call(["ls", "-l"])

# subprocess.check_call("exit 1", shell=True)

  

# 好像没Python废弃了

subprocess.check_output(["echo", "Hello World!"], shell=False)

subprocess.check_output("exit 1", shell=True)

  

# 2、执行复杂的系统相关命令

  

# 1)切换目录再执行命令

obj = subprocess.Popen("mkdir t3", shell=True, cwd='/home/dev',)

  

# 2)有多行且复杂的命令使用三个接口

# obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, 

stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

# obj.stdin.write("print(1)\n")  # 传命令接口

# obj.stdin.write("print(2)")

# obj.stdin.close()

# cmd_out = obj.stdout.read()  # 读接口

# obj.stdout.close()

# cmd_error = obj.stderr.read()  # 读错误接口

# obj.stderr.close()

# print(cmd_out)

# print(cmd_error)

  

# 3)一次读输出

# obj = subprocess.Popen(["python"], stdin=subprocess.PIPE, 

stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

# obj.stdin.write("print(1)\n")

# obj.stdin.write("print(2)")

#

# out_error_list = obj.communicate()

# print(out_error_list)

  

# 4)简单写法

# obj = subprocess.Popen(["python"], stdin=subprocess.PIPE,

stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)

# out_error_list = obj.communicate('print("hello")')

# print(out_error_list) 





xml 是实现不同语言和程序之间进行数据交换的协议



from xml.etree import ElementTree as ET

  

# xml有两个常见格式

# 1)直接读取字符串格式的xml

str_xml = open('xo.xml', 'r').read()

root = ET.XML(str_xml)  # 这里没有建立 xml tree 所以不能直接将内存中的xml写回文件

  

# 2)读取xml格式文件

# tree = ET.parse('xo.xml')  # 首先建立了一个 xml tree 对象

# root = tree.getroot()

# print(root)  # 获取根节点

# print(root.tag)  # 取根节点名

# print(root.attrib)  # 获取节点属性

  

# 3) 遍历多层xml

for child in root:

    print(child.tag, child.attrib)

    for child_second in child:

        print(child_second.tag, child_second.text)  # child_second.text 节点内容

  

# 4) 遍历指定的节点

for node in root.iter('year'):

    print(node.tag, node.text)

  

# 5) 修改节点内容

for node in root.iter('year'):

    new_year = int(node.text) + 1

    node.text = str(new_year)

  

    node.set('name', 'london')

    node.set('age', '18')

  

    del node.attrib['age']

  

tree = ET.ElementTree(root)

tree.write('new_xo.xml', encoding='utf-8')

   

# 6、删除节点

str_xml = open('xo.xml', 'r').read()

root = ET.XML(str_xml)

for country in root.findall('country'):

    rank = int(country.find('rank').text)

    if rank > 50:

        root.remove(country)

  

tree = ET.ElementTree(root)

tree.write('new_xoo.xml', encoding='utf-8')

  

# 7、创建 xml 文档

  

from xml.dom import minidom

  

  

def prettify(elem):

    """将节点转换成字符串,并添加缩进。

    """

    rough_string = ET.tostring(elem, 'utf-8')

    reparsed = minidom.parseString(rough_string)

    return reparsed.toprettyxml(indent="\t")

  

# 创建根节点

root = ET.Element("famliy")

  

# 创建大儿子

# son1 = ET.Element('son', {'name': '儿1'})

son1 = root.makeelement('son', {'name': '儿1'})

# 创建小儿子

# son2 = ET.Element('son', {"name": '儿2'})

son2 = root.makeelement('son', {"name": '儿2'})

  

# 在大儿子中创建两个孙子

# grandson1 = ET.Element('grandson', {'name': '儿11'})

grandson1 = son1.makeelement('grandson', {'name': '儿11'})

# grandson2 = ET.Element('grandson', {'name': '儿12'})

grandson2 = son1.makeelement('grandson', {'name': '儿12'})

  

son1.append(grandson1)

son1.append(grandson2)

  

  

# 把儿子添加到根节点中

root.append(son1)

root.append(son1)

  

raw_str = prettify(root)  # 自动添加缩进

  

f = open("xxxoo.xml", 'w', encoding='utf-8')

f.write(raw_str)

f.close()




configparser 用于处理特定格式的文件 实质上是通过open来操作文件

源文件特定格式


[section1]

k1 = 123

k2 = v2

  

[section2]

k1 = 456

k2 = v2

k3 = v3


常见操作

import configparser

  

# 1、读取文件 读取节点

config = configparser.ConfigParser()

config.read('conf_file', encoding='utf-8')

ret = config.sections()  # 获取所有节点 返回一个列表

ret1 = config.items('section1')  # 读取节点下的键值对

ret2 = config.options('section1')  # 读取某个节点下的键

  

print(ret)

print(ret1)

print(ret2)

  

# 2、读取节点键值

v = config.get('section1', 'k1')  # 获取指定key下的值 默认 str 类型

# v = config.getint('section1', 'k1')

# v = config.getfloat('section1', 'k1')

# v = config.getboolean('section1', 'k1')

print(v, type(v))

  

# 3、检查 添加 删除节点

has_sec = config.has_section('section1')

print(has_sec)

  

# config.add_section('section5')

# config.write(open('conf_file', 'w'))

  

# config.remove_section('section3')

# config.write(open('conf_file', 'w'))

  

# 4、检查 删除 设置 指定组内的键值对

has_opt = config.has_option('section1', 'k1')

print(has_opt)

  

# config.remove_option('section2', 'k3')

# config.write(open('conf_file', 'w'))

  

config.set('section5', 'k1', '123')

config.write(open('conf_file', 'w'))




re 模块

.  匹配除换行符以外的任意字符

\w 匹配字母或数字或下划线或汉字

\s 匹配任意的空白符 

\d 匹配数字

\b 匹配单词的开始或结束 

^  匹配字符串的开始

$  匹配字符串的结束 

*  重复零次或更多次

+  重复一次或更多次 

?  重复零次或一次

{n}   重复n次 

{n,}  重复n次或更多次

{n,m} 重复n到m次 



# import re

   

# match

# print(re.match('com', 'comwww.runcombb').group())  # match 匹配起始位置

# print(re.search('com', 'www.runcombb').group())  # search 匹配第一次位置

  

# sub subn 匹配 替换

# print(re.sub("g.t", "have", 'I get A, get B', 1))  # 1表示只替换1次

# print(re.subn("g.t", "have", 'I get A, get B'))  # 提示替换了几次

  

# split

# print(re.split('\d+', 'one1two2three3four4'))  # 有空格

# 输出

# ['one', 'two', 'three', 'four', '']

  

# compile 封装一个固定匹配规则供多次调用

# s = "JGood is a boy,so cool..."

# r = re.compile(r'\w*oo\w*')   # 查找所有包含oo的单词

# print(r.findall(s))

# 输出:

# ['JGood', 'cool']

  

# 反斜杠

# 在Python中 要进行两次转义才能匹配一个带反斜杠的字符 所以需要4个 \\\\

# print(re.search("\\\\com", "\comcn").group())

  

# 单词

# print(re.findall(r'I\b', 'I&am Ikobe')) # 有很多字符可以用来分隔单词 这里使用&

  

# 分组

# 去已经匹配到的数据中再提取数据

# origin = 'has sdfsdfsdfwer432'

# r = re.match("h\w+", origin)  # 输出:has () {}

# r = re.match("h(\w+)", origin)  # 输出:has ('as',) {}

# r = re.match("h(?P<name>\w+)", origin)  # 输出:has ('as',) {'name': 'as'}

# print(r.group())

# print(r.groups())

# print(r.groupdict())

  

# findall 分组

# origin = "hasaabc halaaabc"

# r = re.findall("h(\w+)a(ab)c", origin)  # 首先整体匹配 再将分组放入结果

# print(r)

# 输出:

# [('as', 'ab'), ('ala', 'ab')]

  

# spilt 分组

# origin = "hello alex abc alex age"

# r = re.split("a(le)x", origin, 1)  # 忽略了alex 直接匹配le

# print(r)

# 输出:

# ['hello ', 'le', ' abc alex age']

常用正则表达式


# IP:

# ^(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}$

  

# 手机号:

# ^1[3|4|5|8][0-9]\d{8}$

  

# 邮箱:

# [a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+



hashlib


# import hashlib

  

# obj = hashlib.md5(bytes('sdfsdfsadf', encoding='utf-8'))  # 加bytes任意字符防止被撞库破译

# obj.update(bytes('123', encoding='utf-8'))

# r = obj.hexdigest()

# print(r)

  

# python内置还有一个 hMac 模块,它内部对我们创建 key 和 内容 进行进一步的处理然后再加密

# import hmac 

  

# h = hmac.new(bytes('898oaFs09f',encoding="utf-8"))

# h.update(bytes('admin',encoding="utf-8"))

# print(h.hexdigest())


os 系统级别的操作

os.getcwd()                 获取当前工作目录,即当前python脚本工作的目录路径

os.chdir("dirname")         改变当前脚本工作目录;相当于shell下cd

os.curdir                   返回当前目录: ('.')

os.pardir                   获取当前目录的父目录字符串名:('..')

os.makedirs('dir1/dir2')    可生成多层递归目录

os.removedirs('dirname1')   若目录为空,则删除,并递归到上一级目录,如若也为空,则删除,依此类推

os.mkdir('dirname')         生成单级目录;相当于shell中mkdir dirname

os.rmdir('dirname')         删除单级空目录,若目录不为空则无法删除,报错;相当于shell中rmdir dirname

os.listdir('dirname')       列出指定目录下的所有文件和子目录,包括隐藏文件,并以列表方式打印

os.remove()                 删除一个文件

os.rename("oldname","new")  重命名文件/目录

os.stat('path/filename')    获取文件/目录信息

os.sep                      操作系统特定的路径分隔符,win下为"\\",linux下为"/"

os.linesep                  当前平台使用的行终止符,win下为"\t\n",Linux下为"\n"

os.pathsep                  用于分割文件路径的字符串

os.name                     字符串指示当前使用平台。win->'nt'; Linux->'posix'

os.system("bash command")   运行shell命令,直接显示

os.environ                  获取系统环境变量

os.path.abspath(path)       返回path规范化的绝对路径

os.path.split(path)         将path分割成目录和文件名二元组返回

os.path.dirname(path)       返回path的目录。其实就是os.path.split(path)的第一个元素

os.path.basename(path)      返回path最后的文件名。如何path以/或\结尾,那么就会返回空值。即os.path.split(path)的第二个元素

os.path.exists(path)        如果path存在,返回True;如果path不存在,返回False

os.path.isabs(path)         如果path是绝对路径,返回True

os.path.isfile(path)        如果path是一个存在的文件,返回True。否则返回False

os.path.isdir(path)         如果path是一个存在的目录,则返回True。否则返回False

os.path.join(path1[, path2[, ...]])  将多个路径组合后返回,第一个绝对路径之前的参数将被忽略

os.path.getatime(path)      返回path所指向的文件或者目录的最后存取时间

os.path.getmtime(path)      返回path所指向的文件或者目录的最后修改时间



sys

用于对Python解释器相关操作:

sys.argv           命令行参数List,第一个元素是程序本身路径

sys.exit(n)        退出程序,正常退出时exit(0)

sys.version        获取Python解释程序的版本信息

sys.maxint         最大的Int值

sys.path           返回模块的搜索路径,初始化时使用PYTHONPATH环境变量的值

sys.platfORM       返回操作系统平台名称

sys.stdin          输入相关

sys.stdout         输出相关

sys.stderror       错误相关

关于sys运用:进度条


def view_bar(num, total):

    rate = num / total

    rate_num = int(rate * 100)

    r1 = '\r%s>%d%%' % ("="*num, rate_num,)  # 加 r 的话让每次输出回到初始最前面位置

    sys.stdout.write(r1)  # 和print的区别就是不加换行符

    sys.stdout.flush()  # 清空屏幕输出

  

for i in range(0, 101):

    time.sleep(0.1)

    view_bar(i, 100) 


python的内置模块中对于命令行的解析模块共两个getopt 和 optparse 。不过getopt过于简单,往往不能满足需求。此时可以使用optparse模块。这个模块相对于getopt更新,功能更强大。

那么如何使用optparse模块呢? optparse 模块的官方文档给出了很详细的说明。


第一步、导入模块,并在主函数中创建实例


from optparse import OptionParser

[...]

parser = OptionParser()


第二步、使用add_option定义需要的option


parser.add_option(opt_str, ...,

                  attr=value, ...)


add_option 方法中有很多可选的参数,及一些影响optparse函数行为的属性。这些东西都很值得去细细推敲。


最后一步、当定义完所有option 后,通过parse_args 去解析所有的option。并返回解析结果


(options, args) = parser.parse_args()


parse_args 默认解析的是sys.argv[1:] 的所有参数。不过若你喜欢,也可以自己传递参数到parse_args。例如如下的形式:

args = ["-f", "foo.txt"]

(options, args) = parser.parse_args(args)


parse_args 有两个返回值,options 和 args 。其中options是一个对象,通过这个对象可以获取到所有定义的option相应信息。而args是一个list,里面存储了所有没有被定义的参数信息。


以上三个步骤,就是使用optparse模块的完整体现。不过在第二步中add_option中存在很多影响pars_args行为的属性,将在下面逐步记录解释。



action 属性:

它将告诉optparse 遇到相应的命令行时应该怎么去做。默认若不指定action属性,它将被赋予默认值store。那么store是什么意义呢?以官方的实例说明

当添加如下的option:


parser.add_option("-f", "--file",

                  action="store", type="string", dest="filename")

且传递如下的参数:


args = ["-f", "foo.txt"]

(options, args) = parser.parse_args(args)

当optparse 发现参数-f 时,它会将-f后面的一个参数也消费掉(将-f 和 foo.txt绑定到一起了)。并将foo.txt存储到options.filename中。当经过parse_args解析后,调用options.filename时将得到foo.txt这个值。


以上是action的默认值store。另外还有布尔类型的action。这样类型的东西主要是在命令行参数不需要值的时候使用。例如 -v 查看版本号, -v 后面就需要再写参数了。

Example:


parser.add_option("-v", action="store_true", dest="verbose")

parser.add_option("-q", action="store_false", dest="quit")

以上两个例子,当经过parse_args后调用options.verbose将为true。而调用options.quit将为false


当然,action还有其他一些值。如:store_const、append、count 和 callback 。研究后再呈上文章吧。

default属性:

给相应的参数设置默认值,也是一个很有必要知道的属性

Example:


parser.add_option("-v", action="store_true", dest="verbose", default=False)

parser.add_option("-q", action="store_false", dest="verbose", default=True)

另外一种比较清晰的方法设置默认值:


parser.set_defaults(verbose=True)

parser.add_option(...)

(options, args) = parser.parse_args()




optparse,是一个能够让程式设计人员轻松设计出简单明了、易于使用、符合标准的Unix命令列程式的Python模块。生成使用和帮助信息。

使用此模块前,首先需要导入模块中的类OptionParser,然后创建它的一个实例(对象):

 

 

from optparse import OptionParser

 

parser = OptionParser()  #这里也可以定义类的参数

例子1:


from optparse import OptionParser

  

def opt():

    parser=OptionParser("Usage: %prog -a command")

    parser.add_option('-a',

                      dest='addr',

                      action='store',

                      help='ip or iprange EX: 192.168.1,192.168.1.3 or192.168.1.1-192.168.1.100')

    options,args=parser.parse_args()

    return options, args

options,args=parser.parse_args()是一个方法返回的是一个元组里面包括选项和参数及options和args

例子2


#!/usr/bin/python

from optparse import OptionParser 

import sys

import os

parser = OptionParser() 

parser.add_option("-c","--char",   

                  dest="chars",

                  action="store_true",

                  default=False,

  

                  help="only count chars")

  

parser.add_option("-w", "--word",

                  dest="words",

                  action="store_true",

                  default=False,

                  help="only count words")

  

parser.add_option("-l", "--line",

                  dest="lines",

                  action="store_true",

                  default=False,

                  help="only count lines")

  

options, args=parser.parse_args()

print options,args


执行这个脚本 python  aa.py

{'chars': False, 'lines': False, 'words': False} []


[root@133 day1]# python hu.py -w hu.py

{'chars': False, 'lines': False, 'words': True}['hu.py']


这个hu.py就代表args  参数。大括号里面的代表options选项

注意:不要用模块的名字做脚本的名字,否则运行时会报错



#!/usr/bin/env python

#coding:utf-8

#对标准输入进行统计

import sys, os

from optparse import OptionParser

 

def opt():

    usage = "usage: %prog [options] arg1 arg2"

    parser = OptionParser()

    parser.add_option("-c", "--char",

                    dest="chars",

                    action="store_true",

                    default=False,

                    help="only count chars")

    parser.add_option("-w", "--word",

                    dest="words",

                    action="store_true",

                    default=False,

                    help="only count words")

    parser.add_option("-l", "--line",

                    dest="lines",

                    action="store_true",

                    default=False,

                    help="only count lines")

    parser.add_option("-n", "--nototal",

                    dest="nototal",

                    action="store_true",

                    default=False,

                    help="nototal")

    options, args = parser.parse_args()

 

    return options, args     

 

opt()

print sys.argv[:]    //打印出脚本运行时的参数,注意和parse_args返回的参数做对比

options, args = opt()

print options, args    //打印出parse_args返回的args的值。





#!/usr/bin/env python

# coding=utf-8

 

import sys, os

from optparse import OptionParser

 

def opt():

    parser = OptionParser()

    parser.add_option("-c", "--char",

                      dest="chars",

                      action="store_true",

                      default=False,

                      help="only count chars")

    parser.add_option("-w", "--ward",

                      dest="words",

                      action="store_true",

                      default=False,

                      help="only count words")

    parser.add_option("-l", "--line",

                      dest="lines",

                      action="store_true",

                      default=False,

                      help="only count lines")

    parser.add_option("-n", "--no-total",

                      dest="nototal",

                      action="store_true",

                      default=False,

                      help="show total or not")

    options, args = parser.parse_args()

    return options, args

 

def get_count(data):

    chars =  len(data)

    words = len(data.split())

    lines = data.count('\n')

    return lines, words, chars

 

def print_wc(options, lines, words, chars, fn):

    if options.lines:

        print lines,

    if options.words:

        print words,

    if options.chars:

        print chars,

    print(fn)

 

def main():

    options, args = opt()

    if not (options.words or options.chars or options.lines):

        options.words, options.chars, options.lines = True, True, True

 

    if args:

        total_lines, total_words, total_chars = 0, 0, 0

        for fn in args:

            if os.path.isfile(fn):

                with open(fn) as fd:

                    data = fd.read()

                lines, words, chars = get_count(data)

                print_wc(options, lines, words, chars, fn)

                total_lines += lines

                total_words += words

                total_chars += chars

            elif os.path.isdir(fn):

                print("%s: is a directory" % fn, file=sys.stderr)

            else:

                sys.stderr.write("%s: No such file or direcotry\n" % fn)

        if len(args) > 1 and not options.nototal:

            print_wc(options, total_lines, total_words, total_chars, 'total')

    else:

        data = sys.stdin.read()

        fn = ''

        lines, words, chars = get_count(data)

        print_wc(options, lines, words, chars, fn)

 

if __name__ == '__main__':

    main()



#!/usr/bin/env python

import sys, os

from optparse import OptionParser

 

parser = OptionParser()

parser.add_option("-c", "--char",

                  dest="chars",

                  action="store_true",

                  default=False,

                  help="only count chars")

 

parser.add_option("-w", "--word",

                  dest="words",

                  action="store_true",

                  default=False,

                  help="only count words")

 

parser.add_option("-l", "--line",

                  dest="lines",

                  action="store_true",

                  default=False,

                  help="only count lines")

 

 

options, args = parser.parse_args()

print options, args

 

data = sys.stdin.read()

chars = len(data)

words = len(data.split())

lines = data.count('\n')

 

if options.chars:

    print chars,

if options.words:

    print words,

if options.lines:

    print lines



parse_args()这个方法返回两个值,options和args,分别是对象和列表,options里包括所有使用parser.add_option()这个方法定义的选项,比如‘-w'。

options.words就是存储'-w'这个选项的,它的值是True或者False,比如脚本后面带-w选项时,那么options.words的值就是True。

下面这个在ipython下的输出,由于没有使用add_option()定义任何选项,所以options的输出里没有选项的值。

这个是python自带的模块,想具体了解它的内部是如何实现的,源码文件在这个位置,/usr/lib64/python2.6/optparse.py。


脚本中这样定义的:dest = "characters",

后面应该这样判断:if options.characters,而不是if options.chars



dest和action有什么用?看Help似乎没怎么提到?

在代码里引用选项时需要dest后面定义的那个名字,比如引用-c选项,就使用options.characters,每个选项都需要dest去定义一个名字,这个值就是选项的名字,目的就是在程序中去引用这个选项,比如:if not (options.characters or options.words or options.lines):括号里就是在引用这些选项。

有的命令后面的选项就是一个字母,有的不仅有字母,而且后面还有值,比较一下下面这两个命令:

wc -l /etc/passwd

tail -n 20 /etc/passwd

-l与-n都是选项,但是行为不一样,-l后面没有值,-n后面有值,那么选项后面带不带值是action决定的,如果action="store_true",那么说明选项后面没有值,如果action='store',说明选项后面需要带值。

脚本后面跟-h时,可以看到help定义的内容。



那default又是有什么作用,为False和True分别表示什么?

拿-c选项举例子,

default如果为True,表示脚本后面如果不加-c选项,默认也是有-c的行为的。

default为False时,表示脚本后面不加-c选项,就没有-c的行为,比如wc -l /etc/hosts,没有-c选项,就说明不对字符统计,只对行数统计




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)删除软链接




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')

sudosudo方式执行远程命令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=PATHSSH配置文件路径

-t N设置连接超时时间,单位秒

-T N设置远程命令超时时间,单位秒

-u USER连接远程主机用户名

-x HOSTS以逗号分隔排除主机

-z INT并发进程数 




本地执行命令


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文件。

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以逗号分隔即可



给脚本函数传入位置参数


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.


主机列表组


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




# 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



上传目录到远程主机



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



 从远程主机下载目录


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


打印颜色,有助于关键地方醒目


from fabric.colors import *


def show():

   print green('Successful.')

   print red('Failure!')

   print yellow('Warning.')

# fab show



pexpect

pexpect是一个用来启动子程序,并使用正则表达式对程序输出做出特定响应,以此实现与其自动交互的Python模块。暂不支持windows下的Python环境执行。

这里主要讲解run()函数和spawn()类,能完成自动交互,下面简单了解下它们使用。


安装Python


download pexpect-2.3.tar.gz

tar zxvf pexpect-2.3.tar.g

cd pexpect-2.3

python setup.py install  (do this as root)


下载pexpect模块:https://pypi.python.org/pypi/pexpect/#downloads

解压后在目录下运行:python ./setup.py install (必须是root权限)

如果没有使用root权限,你只需要把lib的路径放入sys.path,这样便可以使用pexpect


import sys

sys.path.append('pexpect-4.2.1/build/lib')


确认是否安装成功

import pexpect

dir(pexpect)


['EOF', 'ExceptionPexpect', 'Expecter', 'PY3', 'TIMEOUT', '__all__', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__path__', '__revision__', '__version__', 'exceptions', 'expect', 'is_executable_file', 'searcher_re', 'searcher_string', 'split_command_line', 'sys', 'utils', 'which']




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)


run(command,timeout=-1,withexitstatus=False,events=None,extra_args=None,logfile=None, cwd=None, env=None)


函数 run 可以用来运行命令,其作用与 Python os 模块中 system() 函数相似。

run() 是通过 Pexpect 类实现的。


如果命令的路径没有完全给出,则 run 会使用 which 命令尝试搜索命令的路径 。



例1:执行ls命令

>>> import pexpect

>>> pexpect.run("ls") 


例2:获得命令状态返回值

>>> command_output, exitstatus = pexpect.run("ls", withexitstatus=1)


command_outout是执行结果,exitstatus是退出状态值。


使用 run()执行 svn 命令


from pexpect import *


run ("svn ci -m 'automatic commit' my_file.py")


与 os.system() 不同的是,使用 run() 可以方便地同时获得命令的输出结果与命令的退出状态


run() 的返回值


from pexpect import *


(command_output, exitstatus) = run ('ls -l /bin', withexitstatus=1)


command_out 中保存的就是 /bin 目录下的内容



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



spawn() 使用示例


child = pexpect.spawn ('/usr/bin/ftp') #执行ftp客户端命令


child = pexpect.spawn ('/usr/bin/ssh user@example.com') #使用ssh登录目标机器


child = pexpect.spawn ('ls -latr /tmp') #显示 /tmp目录内容


当子程序需要参数时,还可以使用一个参数的列表:


child = pexpect.spawn ('/usr/bin/ftp', [])

child = pexpect.spawn ('/usr/bin/ssh', ['user@example.com'])

child = pexpect.spawn ('ls', ['-latr', '/tmp'])


在构造函数中,maxread 属性指定了 Pexpect 对象试图从 tty 一次读取的最大字节数,它的默认值是2000字节 。

由于需要实现不断匹配子程序输出, searchwindowsize 指定了从输入缓冲区中进行模式匹配的位置,默认从开始匹配。

logfile 参数指定了 Pexpect 产生的日志的记录位置。

记录日志

child = pexpect.spawn('some_command')

fout = file('mylog.txt','w')

child.logfile = fout


还可以将日志指向标准输出:

child = pexpect.spawn('some_command')

child.logfile = sys.stdout

如果不需要记录向子程序输入的日志,只记录子程序的输出,可以使用:

child = pexpect.spawn('some_command')


child.logfile_send = sys.stdout



ftp交互

用ftp命令登录是这样的,需要手动输入用户名和密码,才能登录进去。


# 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帮我们完成输入用户名和密码:


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   # 保存命令执行结果




Python 远程批量修改密码脚本


#tar -zxvf pexpect-3.0.tar.gz

#cd pexpect-3.0

#python setup.py install

#!/usr/bin/env python

#coding:utf8

import pexpect                            

import sys 

iplist = ['192.168.140.142','192.168.140.145'] ##定义主机列表

oldpasswd = '234567' ##旧密码

newpasswd = '1234567' ##新密码

while iplist:

    ip = iplist[-1] ##获取一个IP

    iplist.pop() ##列表去掉一个值

    child = pexpect.spawn('ssh root@'+ip) ##定义触发

    fout = file('passlog.txt','a') ##定义日志文件,

    child.logfile = fout

    try:

        while True:

            index = child.expect(['(yes/no)','(?i)password:'])

            if index == 0:

                child.sendline('yes')

            elif index == 1:

                child.sendline(oldpasswd)

                child.expect('#')

                child.sendline('echo  '+newpasswd+' | passwd --stdin root')

                child.expect('#')

                child.sendline('exit')

    except pexpect.TIMEOUT:

        print >>sys.stderr, ip+' timeout'

    except pexpect.EOF:

        print >>sys.stderr, ip+' <the end>'

(1)spawn类

 class pexpect.spawn(command,args=[],timeout=30,maxread=2000,searchwidowsize=None

,logfile=None,cwd=None,env=None,ignore_sighup=True)

(2)run函数

pexpect.run(command,timeout=-1,withexitstatus=False,events=None,extra_args=None,

logfile=None,cwd=None,env=None).

(3)pxssh类

class pexpect.pxssh.pxssh(timeout=30,maxread=2000,searchwidowsize=None,logfile=None,

cwd=None,env=None)

pxssh常用的三个方法:

    login()建立连接;

    logout()断开连接;

    prompt()等待系统提示符,用于等待命令执行结束



python之pexpect用法及scp新用途


import pexpect

def scp_cmd():

    passwd='*******'

    passwd1='*******'

    ssh = pexpect.spawn('scp -rp root@192.168.1.107:/backup root@192.168.1.102:/data')

    r = ''

    try:

        i = ssh.expect(['password: ', 'continue connecting (yes/no)?'])

        if i == 0 :

            ssh.sendline(passwd)

        elif i == 1:

            ssh.sendline('yes')

            ssh.expect('password:')

            ssh.sendline(passwd)

        b=ssh.expect(['password: ','continue connecting (yes/no)?'])

        if b==0:

            ssh.sendline(passwd1)

        elif b==1:

            ssh.sendline('yes')

            ssh.expect('password:')

            ssh.sendline(passwd1)

    except pexpect.EOF:

        ssh.close()

    else:

        r = ssh.read()

        ssh.expect(pexpect.EOF)

        ssh.close()

    return r

scp_cmd()




python安装setuptools模块之后,便可使用easy_install来安装python的第三方扩展模块,默认安装路径是:

/usr/lib/python2.6/site-packages/


easy_install 模块名 #可以直接安装

easy_install  pexpect

[root@zhu ~]# easy_install pexpect

Searching for pexpect

Reading http://pypi.python.org/simple/pexpect/

Reading http://pexpect.readthedocs.org/

Reading http://pexpect.sourceforge.net/

Reading http://sourceforge.net/project/showfiles.PHP?group_id=59762

Best match: pexpect 3.1

Downloading https://pypi.python.org/packages/source/p/pexpect/pexpect-3.1.tar.gz#md5=5a8e1573062e2e2c203c9a6d213b16e7

Processing pexpect-3.1.tar.gz

Running pexpect-3.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-KOPmVQ/pexpect-3.1/egg-dist-tmp-GnQBTg

zip_safe flag not set; analyzing archive contents...

Adding pexpect 3.1 to easy-install.pth file

Installed /usr/lib/python2.6/site-packages/pexpect-3.1-py2.6.egg

Processing dependencies for pexpect

Finished processing dependencies for pexpect


#由于pexpect-3.1-py2.6.egg此时仍是一个压缩文件,所以需要进行解压。

cd /usr/lib/python2.6/site-packages/

unzip pexpect-3.1-py2.6.egg



pexpect是一个用来启动子程序并对其进行自动控制的python模块,可以用来和ssh,ftp,telnet等需要输入密码的命令行程序进行自动交互。

安装过程如上。


另一种安装方法如下:



wget http://pexpect.sourceforge.net/pexpect-2.3.tar.gz

 tar xzf pexpect-2.3.tar.gz

 cd pexpect-2.3

 python ./setup.py install



pexpect 模块的使用如下:



>>> pexpect.

pexpect.EOF(                 pexpect.__path__             pexpect.run(

pexpect.ExceptionPexpect(    pexpect.__reduce__(          pexpect.runu(

pexpect.PY3                  pexpect.__reduce_ex__(       pexpect.searcher_re(

pexpect.TIMEOUT(             pexpect.__repr__(            pexpect.searcher_string(

pexpect.__all__              pexpect.__revision__         pexpect.select

pexpect.__class__(           pexpect.__setattr__(         pexpect.signal

pexpect.__delattr__(         pexpect.__sizeof__(          pexpect.spawn(

pexpect.__dict__             pexpect.__str__(             pexpect.spawnu(

pexpect.__doc__              pexpect.__subclasshook__(    pexpect.split_command_line(

pexpect.__file__             pexpect.__version__          pexpect.struct

pexpect.__format__(          pexpect._run(                pexpect.sys

pexpect.__getattribute__(    pexpect.codecs               pexpect.termiOS

pexpect.__hash__(            pexpect.errno                pexpect.time

pexpect.__init__(            pexpect.fcntl                pexpect.traceback

pexpect.__loader__           pexpect.os                   pexpect.tty

pexpect.__name__             pexpect.pty                  pexpect.types

pexpect.__new__(             pexpect.re                   pexpect.which(

pexpect.__package__          pexpect.resource


1.pexpect.run()函数的使用



run(command, timeout=-1, withexitstatus=False, events=None, extra_args=None, logfile=None, cwd=None, env=None)


#默认情况下该指令:

#1.运行给出的指令command,如果指令不是以绝对路径给出,会自动在PATH中寻找。结果输出作为字符串返回,行与行之间以\r\n分割。

#2.withexitstatus设置为True时,结果返回一个元组,(command_output,

    exitstatus)


#events是一个字典,有模式和应答组成,可以自动输入内容,如果应答需要输入enter键时,此时需要为一个新行,即添加\n.

>>> pexpect.run('cat /root/a.txt')

'qian shan\r\nniao fei jue\r\ndu diao han jiang xue\r\n'

>>> pexpect.run('cat /root/a.txt',withexitstatus=1)

('qian shan\r\nniao fei jue\r\ndu diao han jiang xue\r\n', 0)

>>> pexpect.run('scp /root/a.txt 192.168.56.102:/root',withexitstatus=1,events={'password': '123456\n'})

("root@192.168.56.102's password: \r\n\ra.txt                                           0%    0     0.0KB/s   --:-- ETA\ra.txt                                         100%   45     0.0KB/s   00:00    \r\n", 0)





2.pexpect.spawn()类的使用

spawn是Pexpect模块主要的类,用以实现启动子程序,它有丰富的方法与子程序交互从而实现用户对子程序的控制。它主要使用 pty.fork() 生成子进程,并调用 exec() 系列函数执行 command 参数的内容。



child = pexpect.spawn ('/usr/bin/ftp') #执行ftp客户端命令

child = pexpect.spawn ('/usr/bin/ssh user@example.com') #使用ssh登录目标机器

child = pexpect.spawn ('ls -latr /tmp') #显示 /tmp目录内容

child = pexpect.spawn ('/usr/bin/ftp', [])

child = pexpect.spawn ('/usr/bin/ssh', ['user@example.com'])

child = pexpect.spawn ('ls', ['-latr', '/tmp'])

child = pexpect.spawn('some_command')

fout = file('mylog.txt','w')


child.logfile = fout



child = pexpect.spawn('ssh root@192.168.56.102')


child.expect(self, pattern, timeout=-1, searchwindowsize=-1)


为了控制子程序,等待子程序产生特定输出,做出特定的响应,可以使用 expect 方法

在参数中: pattern 可以是正则表达式, pexpect.EOF , pexpect.TIMEOUT ,或者由这些元素组成的列表。需要注意的是,当 pattern 的类型是一个列表时,且子程序输出结果中不止一个被匹配成功,则匹配返回的结果是缓冲区中最先出现的那个元素,或者是列表中最左边的元素。使用 timeout 可以指定等待结果的超时时间 ,该时间以秒为单位。当超过预订时间时, expect 匹配到pexpect.TIMEOUT。



3.打印before的内容


>>> child = pexpect.spawn('ls -l')

>>> child.expect(pexpect.EOF)

0

>>> print child.before

总用量 64

drwxr-xr-x.  3 root root  4096 4月   2 10:09 aaa

-rw-r--r--.  1 root root    45 4月   3 15:01 a.txt

drwxr-xr-x. 16 root root  4096 3月   6 21:36 biaozhunku

drwxr-xr-x.  2 root root  4096 3月  27 17:03 mypython

drwxr-xr-x.  2 root root  4096 4月   3 13:21 mysource

drwxr-xr-x.  2 root root  4096 4月   3 13:20 mywork

drwxr-xr-x.  2 root root 36864 3月  19 11:09 pythoncook

-rw-r--r--.  1 root root   276 4月   3 14:26 zhu.py

#child.before 保存的就是在根目录下执行 ls 命令的结果


send(self, s)

sendline(self, s='')

sendcontrol(self, char)


这些方法用来向子程序发送命令,模拟输入命令的行为。与 send() 不同的是 sendline() 会额外输入一个回车符 ,更加适合用来模拟对子程序进行输入命令的操作。当需要模拟发送 “Ctrl+c” 的行为时,还可以使用 sendcontrol() 发送控制字符。



手动输入时,是来自键盘的标准输入,而pexpect是先匹配到关键字,再向子进程发送字符串。

pexpect.EOF打印提示信息,child.before保存的是命令执行结果。


通过上面的例子想必你已经知道pexpect主要功能了,在交互场景下很有用,这里就讲解这么多了,目的是给大家提供一个自动交互实现思路。

小结:

通过对Python下paramiko、fabric和pexpect模块使用,它们各有自己擅长的一面。

paramiko:方便嵌套系统平台中,擅长远程执行命令,文件传输。

fabric:方便与shell脚本结合,擅长批量部署,任务管理。

pexpect:擅长自动交互,比如ssh、ftp、telnet。


--结束END--

本文标题: Python批量管理主机(paramik

本文链接: https://lsjlt.com/news/186432.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • Python批量管理主机(paramik
    paramikoparamiko模块是基于Python实现的SSH远程安全连接,用于SSH远程执行命令、文件传输等功能。默认Python没有,需要手动安装:pip install paramiko如安装失败,可以尝试yum安装:yum in...
    99+
    2023-01-31
    批量 主机 Python
  • python实现主机批量管理
        在日常的运维工作中批量对主机的是很常见的,市面上也有许多主机批量管理的软件,但有时候这些软件并不能完全的满足我们的需求。python中刚好提供了关于主机批量管理的模块,今天就让我们来看看如何利用python实现主机批量管理pytho...
    99+
    2023-01-31
    批量 主机 python
  • 详解python之简单主机批量管理工具
    今天做了一个很简单的小项目,感受到了paramiko模块的强大,也深感自己Linux的功力不行~~ 一、需求 二、简单需求分析及流程图 需求很少,我就简单地说下: 1. 主机分组可以配置文件实现(...
    99+
    2022-06-04
    管理工具 批量 详解
  • 批量管理python脚本
    新出炉的脚本, 有错的地方还望指出,谢谢。 #!/usr/bin/env python # -*- coding: utf-8 -*- # #  Syscloud Operation platform.py #...
    99+
    2023-01-31
    批量 脚本 python
  • python 批量修改主机名
    公司需要新上项目,上架20台机器,要对这些主机进行改名#!/usr/bin/env python from multiprocessing import Process, Pool import paramiko import sys,os...
    99+
    2023-01-31
    批量 主机名 python
  • 批量远程桌面管理 批量管理服务器
    批量远程桌面管理 批量管理服务器远程桌面是微软公司为了便于网络管理员管理维护服务器推出的一项服务。从windows 2000 server版本开始引入,网络管理员时候远程桌面连接器连接到网络任意一台开启了远程桌面控制功能的计算机上,就像是自...
    99+
    2023-06-03
  • linux服务器批量管理工具 批量vps管理
    linux服务器批量管理工具 批量vps管理远程桌面是微软公司为了便于网络管理员管理维护服务器推出的一项服务。从windows 2000 server版本开始引入,网络管理员时候远程桌面连接器连接到网络任意一台开启了远程桌面控制功能的计算机...
    99+
    2023-06-03
  • 批量远程桌面管理软件 批量管理服务器
    批量远程桌面管理软件 批量管理服务...
    99+
    2024-04-02
  • 虚拟主机是否支持多域名SSL证书批量管理
    是的,虚拟主机可以支持多域名SSL证书批量管理。许多虚拟主机提供商提供了SSL证书管理工具,允许用户轻松管理多个域名的SSL证书。用户可以在虚拟主机控制面板或SSL证书管理工具中添加、删除和更新多个域名的SSL证书,确保网站的安全性和可信度...
    99+
    2024-07-04
    虚拟主机
  • vps批量采购 批量服务器管理
    vps批量采购 批量服务器管理远程桌面是微软公司为了便于网络管理员管理维护服务器推出的一项服务。从windows 2000 server版本开始引入,网络管理员时候远程桌面连接器连接到网络任意一台开启了远程桌面控制功能的计算机上,就像是自己...
    99+
    2023-06-03
  • python 利用paramiko批量管
    paramiko是基于python实现的ssh2远程安全连接,支持秘钥认证,实现远程命令执行,文件传输,中间ssh代理等功能安装paramikoparamiko依赖第三方的crypto,ecdsa,python-develyum insta...
    99+
    2023-01-31
    批量 python paramiko
  • 批量远程桌面 批量服务器管理
    批量远程桌面 批量服务器管理 远程...
    99+
    2024-04-02
  • 批量服务器bios 批量服务器管理
    批量服务器bios 批量服务器管理远程桌面是微软公司为了便于网络管理员管理维护服务器推出的一项服务。从windows 2000 server版本开始引入,网络管理员时候远程桌面连接器连接到网络任意一台开启了远程桌面控制功能的计算机上,就像是...
    99+
    2023-06-03
  • 批量远程登录windows 批量管理服务器
    批量远程登录windows 批量管理服务器远程桌面是微软公司为了便于网络管理员管理维护服务器推出的一项服务。从windows 2000 server版本开始引入,网络管理员时候远程桌面连接器连接到网络任意一台开启了远程桌面控制功能的计算机上...
    99+
    2015-05-16
    批量远程登录windows 批量管理服务器
  • 服务器管理口 批量管理程序
    查看地址: iis7远程桌面管理工具下载 首先,下载解压软件: 点击右上角的【添加】添加服务器的相关信息: 下面是你必须要添加的服务器信息: 【注意】 1 、 输入服务器端口后用冒号分隔再填写端口号(一般默认为 3389 ); 2 、...
    99+
    2015-04-24
    服务器管理口 批量管理程序
  • 服务器管理软件 vps批量管理
    远程桌面是微软公司为了便于网络管理员管理维护服务器推出的一项服务。从windows 2000 server版本开始引入,网络管理员时候远程桌面连接器连接到网络任意一台开启了远程桌面控制功能的计算机上,就像是...
    99+
    2024-04-02
  • window主机如何批量301跳转
    window主机批量301跳转的方法:在httpd.ini配置文件中另写一行重定向代码,例如将域名“123.com”、“www.456.com”都重定向到“www.123.com”,代码如下:[ISAPI_Rewrite]CacheCloc...
    99+
    2024-04-02
  • 如何实现批量vps管理
    这篇文章主要介绍了如何实现批量vps管理的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇如何实现批量vps管理文章都会有所收获,下面我们一起来看看吧。首先,下载解压iis7远程桌面管理工具:点击右上角的【添加】添...
    99+
    2023-06-02
  • 如何批量管理服务器
    小编给大家分享一下如何批量管理服务器,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下面让我们一起去了解一下吧!首先,下载解压软件:点击右上角的【添加】添加服务器的相关信息:下面是你必须要添加...
    99+
    2023-06-02
  • mstsc服务器批量管理好友 vps服务器批量
    查看地址: iis7远程桌面管理工具下载 首先,下载解压软件: 点击右上角的【添加】添加服务器的相关信息: 下面是你必须要添加的服务器信息: 【注意】 1 、 输入服务器端口后用冒号分隔再填写端口号(一般默认为 3389 ); 2 、...
    99+
    2016-05-06
    mstsc服务器批量管理好友 vps服务器批量
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作