设为首页 收藏本站
查看: 2235|回复: 0

[经验分享] Python批量管理主机(paramiko、fabric与pexpect)

[复制链接]

尚未签到

发表于 2018-8-8 13:51:33 | 显示全部楼层 |阅读模式
  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:

  >  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,>  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。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-548752-1-1.html 上篇帖子: 【python】python代码的缩进 下篇帖子: Python 压力测试脚本
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表