VBS 中变量设置为变量的问题
在我与 SecureCRT 结合使用来自动化 Cisco 设备上的某些流程的 VBS 中,我(非常精简)了以下代码:
Sub prConnectToHost(strConnectHost)
'If no host is passed into subroutine then we need to prompt for one.
If strConnectHost = "" Then strConnectHost = LCase(crt.Dialog.Prompt("Enter hostname or IP address:", "Connect to a host", strHost, False))
strHost = strConnectHost
'If user hits Cancel or hits Ok with no hostname entered then exit.
If strHost = "" Then
booReconnect = False
Exit Sub
End If
'Write to connection log
Call prWriteToConnectionLog
'Run command capture subroutine.
Call prCommandLoop
Set intWaitString = Nothing: Set strScreenGet = Nothing
Set strLatestScriptVersion = Nothing: Set strConnectHost = Nothing
End Sub
Sub Main 有一个像这样的部分:
Do While booReconnect = True
Call prConnectToHost("")
Loop
crt.Dialog.Prompt 与
MsgBox
相同,只是它以窗口为中心而不是以屏幕为中心,所以它更整洁一些。变量 strHost
是实际的主机名字符串,它在脚本中是全局的,包含我们要连接的主机名。它在 Prompt
行中用作默认文本,其想法是,如果您断开连接并设置了 booReconnect
标志,则此 Sub
是再次调用,下次提示您输入主机名时,旧主机名就在那里 - 如果您第一次拼写错误,或者您正在连接到一堆具有相似名称的设备,那么这很有用。
您可以看到我们在此 Sub
末尾调用 prCommandLoop
的位置,这是一个使用名为 WaitForStrings
crt 函数
的循环/code> 它将搁置脚本,直到找到特定的字符串序列。当它发生时,它会发射一些东西,然后循环回来,直到再次等待。
其中一个自动化命令会检测连接菜单是否存在(因此我们已退出路由器会话)并提示用户输入另一个要连接的主机名。
重要的一点是最后的变量清除 - Set strConnectHost = Nothing
。如果我保留此设置并立即退出设置了 booReconnect
的 prCommandLoop
,那么一旦应用 Set strConnectHost = Nothing
,strHost 死亡 - 如果我尝试引用它,我会收到错误
未设置对象变量
。我尝试将 MsgBox strHost
行放在 Sub
的末尾,这证明了这一点。
奇怪的是,如果我首先在 prCommandLoop 中选择不同的自动化命令,然后退出会话,则 Set strConnectHost = Nothing 似乎不会打扰任何人。
谁能帮我解释为什么这是一个问题,因为它让我感到困惑。我可以轻松解决这个问题(通过不在 prConnectToHost
Sub 末尾发出 Set strConnectHost = Nothing
),但我只想了解问题所在。
In a VBS I have which I use in conjunction with SecureCRT to automate some processes on Cisco devices, I have (very much pared down) the following code:
Sub prConnectToHost(strConnectHost)
'If no host is passed into subroutine then we need to prompt for one.
If strConnectHost = "" Then strConnectHost = LCase(crt.Dialog.Prompt("Enter hostname or IP address:", "Connect to a host", strHost, False))
strHost = strConnectHost
'If user hits Cancel or hits Ok with no hostname entered then exit.
If strHost = "" Then
booReconnect = False
Exit Sub
End If
'Write to connection log
Call prWriteToConnectionLog
'Run command capture subroutine.
Call prCommandLoop
Set intWaitString = Nothing: Set strScreenGet = Nothing
Set strLatestScriptVersion = Nothing: Set strConnectHost = Nothing
End Sub
Sub Main has a section like this:
Do While booReconnect = True
Call prConnectToHost("")
Loop
crt.Dialog.Prompt
is the same as MsgBox
, only it centres on the window and not the screen, so it's a little neater. The variable strHost
is the actual hostname string which is global in the script and contains the hostname we want to connect to. It is used in the Prompt
line as a default text, the idea being that if you disconnect and the booReconnect
flag is set, this Sub
is called again, and next time you're prompted for a hostname the old one is there - useful if you spelled it wrong first time, or you're connecting to a bunch of devices with a similar name.
You can see where we call prCommandLoop
at the end of this Sub
, which is a loop which uses a crt Function
called WaitForStrings
which puts the script on hold until it finds a particular string sequence. When it does, it fires off some stuff, then loops back around until it sits waiting again.
One of the automation commands detects for the presence of the connection menu (so therefore we have quit the router session) and prompts the user for another hostname to connect to.
The important bit is in the variable clearup at the end - Set strConnectHost = Nothing
. If I leave this in and immediately exit prCommandLoop
with booReconnect
set, as soon as Set strConnectHost = Nothing
is applied, strHost
dies - if I try to reference it I get an error Object Variable not set
. I experimented with putting a MsgBox strHost
line right at the end of the Sub
, which proved this.
The bizarre thing is that if I choose a different automation command in prCommandLoop
first and then quit the session, the Set strConnectHost = Nothing
doesn't seem to bother anyone.
Can anyone help me explain why this is a problem, as it is baffling me. I can easily work around it (by not issuing Set strConnectHost = Nothing
at the end of the prConnectToHost
Sub), but I just want to understand what the problem is.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
Set用于将对象分配给变量。将 Nothing 视为一个非常特殊的对象
,它仅用于指示变量为空。您
将此 Nothing 分配给 strConnectHost。之后,该变量就毫无用处了——它保存着无法打印或在计算中使用或要求执行方法的空对象。
类型前缀欺诈 (*str*ConnectHost) 应提醒您这是可疑的。您使用字符串(和数字?);要清除/重置它们,请使用(简单)分配 Empty:
或合适的值:(
假设 intWaitString 不是另一种类型前缀欺诈)。
第二次尝试:
我假设您像这样调用您的子程序:
您的子程序的相关摘要是:
由于 VBScript 默认使用参数的引用传递,因此您的修改
更改调用者变量 strHost。这也发生在非对象变量上:
输出:
在您的情况下,修改不会将任何内容分配给被调用的变量
Sub 中的 strConnectHost 和调用者级别的 strHost。正如我之前所说,
这使得该变量毫无用处(除了测试 Is Nothing 之外)。
我希望这能解释 strHost 的破坏。
WRT‘内存管理’:除了非常特殊的情况,你不需要
VBScript 中的清除/重置/SetToNothing 变量。在你的程序中使用局部变量
子/函数就是所需要的。如果您决定使用全局变量
并自己管理它们的状态,您必须注意变量类型:
改变对象的类型(包括Nothing)<=>非对象和说谎
通过误导性类型前缀来了解类型是危险的/肯定会导致灾难。
如果您认为必须清除 strHost,请将 Empty 或“”分配给 strConnectHost。
下一个补充
所有 VBScript 变量都是变体,但并非所有变体都是相同的:
TypeName() 和 VarType() 显示子类型,程序员可以使用一组
C[hange/onvertTo]()
函数强制执行它们 - 在某种程度上,作为赋值可能会“在幕后”改变类型。
甚至还有类型不匹配错误:
所以子类型很重要。有些人认为类型前缀不酷,但其他人认为
它们对于弱类型语言来说是有价值的帮助。如果您决定使用它们,您
应该正确使用它们 -
所有的味道(不注意类型并且很难确定后面代码中的错误)。
Set is used to assign objects to variables. Think of Nothing as a very special object
which is useful only to indicate the emptiness of the variable. Your
assigns this Nothing to strConnectHost. After that, the variable is good for nothing - it holds the empty object that can't be printed or used in computations or asked to do methods.
The type prefix fraud (*str*ConnectHost) should alert you that this is fishy. You work with strings (and numbers?); to clear/reset them use (simple) assignment with Empty:
or with a suitable value:
(assuming intWaitString isn't another type prefix fraud).
SECOND ATTEMPT:
I assume you call your sub like this:
The relevant digest of your sub is:
As VBScript uses by reference passing of parameters as default, your modification
changes the caller variable strHost. This happens to non-object variables too:
output:
In your case the modification assigns Nothing to the variable that is called
strConnectHost in the Sub and strHost on the caller level. As I said before,
that makes the variable useless (except of testing for Is Nothing).
I hope that explains the clobbering of strHost.
WRT 'memory management': Except for very special cases, you don't need to
clear/reset/SetToNothing variables in VBScript. Using local variable in your
Subs/Functions is all that is necessary. If you decide to use global variables
and manage their state yourself, you must pay attention to the variable types:
Changing the type from object (including Nothing) <=> non-object and lying
about types by misleading type prefixes is dangerous/a sure way to desaster.
If you think you must clear strHost, assign Empty or "" to strConnectHost.
NEXT ADDITION
All VBScript variables are Variants, but not all Variants are created equal:
TypeName() and VarType() show the sub-types and a progammer can use a set of
C[hange/onvertTo]<Type>()
functions to enforce them - to a degree, as assignmentsmay change types 'under the hood'.
There are even Type Mismatch Errors:
So sub-types matter. Some people think type prefixes are uncool, but others see
them as valuable help in weakly typed languages. If you decide to use them, you
should use them correctly -
all smell (of not paying attention to types and hard to pin down errors in later code).