我正在编写一个简单的 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”的管理方式有关吗?我搜索了相关信息,但没有发现任何关于这个特定论点有意义的内容。
这与错误处理无关。注意
c_ls
的范围 - 在第一个示例中,您在循环之外打开文件,因此对象被创建一次,当您迭代它时,它会在第一次迭代后耗尽,不再执行任何命令对于其余的主机。然而,在第二段代码中,您将在该循环内打开文件,这意味着为每个主机创建一个新的 c_ls
对象,因此它包含要迭代的所有命令。
open() 函数返回一个文件对象,可用于迭代文件中的行。不过,您只能迭代它们一次。在外循环的第一次迭代中,您将迭代它们,耗尽迭代器。从第二次迭代开始,没有元素剩余。
解决方案:要么在外循环的每次迭代中重新打开文件(您在第二个代码示例中所做的),要么更好地将命令存储在列表中,该列表可以一次又一次地迭代:
with open(commands, "r") as f:
c_ls = f.readlines()
(使用“with”可以确保即使在出现异常的情况下也能正确关闭文件)
编辑: f.readlines() 比 list(f) 更清晰。