嵌套for循环只执行一次
我正在写一个简单的Python:Pexpect脚本,目的是替代我以前用的一个老旧的TCL:Expect脚本,这个脚本用来向我们的网络交换机推送配置更改或命令。
如果我写:
h_ls = open(hostls,"r")
c_ls = open(commands,"r")
for host in h_ls:
host = host.strip()
try:
s = pxssh.pxssh(timeout=5,logfile = sys.stdout,options={
"StrictHostKeyChecking": "no",
"UserKnownHostsFile": "/dev/null",
"AddKeysToAgent": "yes"},encoding='utf-8')
s.login (host, user, password,\
auto_prompt_reset=False,\
original_prompt=r'.*#')
print (">>>>> Working on "+host+" @ "+str(now)+" <<<<<\n")
s.prompt()
for cmd in c_ls:
s.sendline(cmd+"\n")
s.prompt()
print(s.before)
s.logout()
except pxssh.ExceptionPxssh as e:
print("***pxssh failed on login***")
#traceback.print_exc()
print("***"+str(e)+" "+host+"***")
那么“commands”变量里的命令只会在“hostls”列表的第一个主机上执行一次。
但如果我写:
h_ls = open(hostls,"r")
for host in h_ls:
host = host.strip()
try:
s = pxssh.pxssh(timeout=5,logfile = sys.stdout,options={
"StrictHostKeyChecking": "no",
"UserKnownHostsFile": "/dev/null",
"AddKeysToAgent": "yes"},encoding='utf-8')
s.login (host, user, password,\
auto_prompt_reset=False,\
original_prompt=r'.*#')
print (">>>>> Working on "+host+" @ "+str(now)+" <<<<<\n")
s.prompt()
c_ls = open(commands,"r")
for cmd in c_ls:
s.sendline(cmd+"\n")
s.prompt()
print(s.before)
s.logout()
except pxssh.ExceptionPxssh as e:
print("***pxssh failed on login***")
#traceback.print_exc()
print("***"+str(e)+" "+host+"***")
那么这些命令就会在“hostls”变量里的每个主机上正确执行。
我到底哪里没理解呢?
为了完整起见,在这个脚本的Tcl:Expect版本中,我的逻辑和第一个例子类似,而且它运行得很好,所以我可能在Python的知识上有些欠缺。这和“try except”块的处理方式有关吗?我查了一些资料,但没有找到关于这个特定问题的有用信息。
2 个回答
1
这不是关于错误处理的问题。注意一下c_ls
的作用范围。在第一个例子中,你是在循环外打开文件的,这样对象只创建了一次,当你开始遍历它时,第一次遍历就把内容用完了,之后就没有命令可以执行给剩下的主机了。而在第二段代码中,你是在循环里面打开文件,这意味着每次处理一个主机时,都会创建一个新的c_ls
对象,这样它就包含了所有可以遍历的命令。
1
open()函数会返回一个文件对象,这个对象可以用来逐行读取文件的内容。不过,你只能读取一次。在第一次循环中,你会读取所有的行,这样迭代器就用完了。从第二次循环开始,就没有内容可以读取了。
解决办法是:要么在每次外部循环时重新打开文件(这在你的第二段代码中已经做到了),要么更好的是把命令存储在一个列表里,这样可以多次读取:
with open(commands, "r") as f:
c_ls = f.readlines()
(使用'with'可以确保即使出现异常,文件也能被正确关闭)
补充:f.readlines()比list(f)更清晰。