在Python中,for循环一个文件来搜索另一个

时间:2015-03-10 19:33:45

标签: python paramiko readlines

非常感谢如何增强我的python脚本以解决问题。我有一个文件,其中列出了数千个移动工作站和IP地址,每五分钟更新一次。我使用Paramiko进入每个工作站以验证服务是否正在运行(在此示例中为crond)。我遇到的问题是当我启动我的python脚本时,它将大文件读入内存,当它获得1/3的时候,IP地址已经改变,并且大部分IP地址不再有效。有没有办法让python打开然后在工作站每次搜索之前关闭文件?这将确保IP是当前的IP。我在下面写的python脚本有效,但我再次遇到旧IP信息的问题。谢谢。

The contents of WKSIPS.txt are in the format:

WORK  1234  Cell IP: 10.10.10.10
WORK  4567  Cell IP: 10.10.10.11

#!/usr/bin/python
import paramiko, os, string, threading
import getpass
import socket
import sys

FileName=open('WKSIPS.txt', 'r')
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

for line in FileName.readlines():
    WKSid = line.split()
    try:
        if WKSid[0] == 'WORK' :
            WKSip = WKSid[4]   
            ssh.connect(WKSip, username='user', password='password', timeout='3')
            stdin, stdout, stderr = ssh.exec_command('service crond status')
            Out =  stdout.readlines()
            print ("WORK  " + WKSid[1], Out)
            ssh.close()
            FileName.close
   except paramiko.SSHException, e:
       print ('WORK' + WKSid, WKSip, "Invalid Password")

2 个答案:

答案 0 :(得分:2)

我建议使用multiprocessing pool创建可以为您处理文件每一行的工作人员,这样可以更快地完成文件。

我使用此代码段的目标是完全避免文件重新加载问题,方法是让您的脚本足够快,以便在5分钟文件刷新之前完成。

#!/usr/bin/python

import paramiko, os, string, threading
import multiprocessing
import getpass
import socket
import sys

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

def worker(line)
    WKSid = line.split()
    try:
        if WKSid[0] == 'WORK' :
            WKSip = WKSid[4]

            ssh.connect(WKSip, username='user', password='password', timeout='3')
            stdin, stdout, stderr = ssh.exec_command('service crond status')
            Out =  stdout.readlines()
            print ("WORK  " + WKSid[1], Out)
            ssh.close()
    except paramiko.SSHException, e:
        print ('WORK' + WKSid, WKSip, "Invalid Password")

# set up processing pool
pool = multiprocessing.Pool()

with open('WKSIPS.txt') as infile:
    pool.map(worker, infile)

pool.close()
pool.join()

注意:

  • 我已将脚本功能的主要部分移动到一个函数中,该函数接受文件的一行作为输入。 pool.map()将为每个worker提供文件迭代器的一行,并且它们将独立处理它。它与原始代码的功能相同,但工作分为多个进程,这些进程等于计算机上的内核数。
  • 我没有paramiko模块,无法在我当前的环境中安装它,所以我无法真正为您测试此代码。如果有任何错误,我会提前道歉。
  • 我不熟悉paramiko库,因此在多个进程中同时使用相同的paramikio.SSHClient()对象可能会产生一些隐藏的副作用。如果您看到来自ssh对象的奇怪错误,请尝试将其实例化移动到辅助函数中。
  • 我已将readlines()更改为使用Python文件迭代器。将整个文件读入内存是一项耗时的操作,应该避免使用。

为了清楚起见,此代码段不会处理文件运行时发生的更改。我做了两个很大的假设:

  1. 执行此脚本可以与刷新文件的任何操作同步,以便在刷新文件后立即执行。
  2. 它可以在5分钟内执行 - 因为我没有paramiko,访问ssh目标或访问WKSIPS.txt,所以我无法计时。由于这个问题似乎符合embarassingly parallel的定义,我认为值得一试。如果不符合时间规范,将由OP进一步优化。

答案 1 :(得分:0)

非常昂贵,但我认为这是看看这种方法是否适合您的第一步:

import re
import paramiko

def verify_service(ssh, work, ip):
    print("Verifying workstation %d at %s" % (work, ip))
    ssh.connect(ip, username='user', password='password', timeout='3')
    stdin, stdout, stderr = ssh.exec_command('service crond status')
    print ("WORK  " + work, stdout.readlines())
    ssh.close()

IP_LIST = 'WKSIPS.txt'
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())

# Get number of lines in WKSIPS -- if you know this, you can just define NUM_LINES
NUM_LINES = None
with open(IP_LIST) as f:
    NUM_LINES = len(f.readlines())

for i in xrange(NUM_LINES):
    with open(IP_LIST) as f:
        #line = f.readlines()[i]
        line = next(islice(f, i, None))
        mat = re.match(r'WORK\s*(\d+)\s*Cell IP: (.*)', line)
        if mat:
            verify_service(ssh, int(mat.group(1)), mat.group(2))

代码首先打开您的文件并计算行数,并将其存储在NUM_LINES中。如果您知道这个号码,就可以摆脱NUM_LINES = None行及其下面的两行,只需将其替换为NUM_LINES = <number of lines>

然后,对于0和i之间的每个行号NUM_LINES(不包括),它会打开文件, 将整个文件读入列表,拉动对应于行号i 的行重复行直到它到达i行,解析它并将其传递给verify_service()函数 - 你和#39;我必须使用您的paramiko代码进行更新。

如果这样做,你应该考虑更好的方法来做到这一点。也许您不必每次迭代都重新读取文件,也许每个 n 迭代都可以正常工作。也许您在重新读取之前对文件进行散列并检查散列是否已更改。也许您检查文件的修改时间等。也许您使用子进程并尝试同时处理多个连接而不是连续处理。

在任何情况下,如果这样做,你应该考虑优化它 - 因为它目前的编写非常昂贵,但它会做你所说的你想要的。