【发布时间】:2014-10-31 21:37:05
【问题描述】:
我正在尝试在 VBscript 中处理/过滤输入,但仅如果输入已通过管道传输到脚本中。我不希望脚本处理用户/键盘输入。我想把它编码成这样:
stdin_is_tty = ...
if not stdin_is_tty then
...
input = WScript.StdIn.ReadAll
end if
否则,脚本将挂起,在执行 WScript.StdIn.ReadAll 时等待用户输入(如果我使用 WScript.StdIn.AtEndOfStream 测试流,甚至更早)。
在 C# 中,我会使用:
stdin_is_tty = not System.Console.IsInputRedirected // NET 4.5+
Q: "How to detect if Console.In (stdin) has been redirected?" 的 accepted answer 显示了如何使用 Win32 调用通过 P/Invoke 构建该结果,用于 NET 4.5 之前的 NET 版本。但我不知道有什么方法可以将该方法转换为 VBscript。
我构建了一个笨拙的部分解决方案,使用SendKeys 将流结束序列发送到脚本的键盘缓冲区。但是如果 STDIN is 被重定向,解决方案会将键留在缓冲区中,除非我知道 STDIN 被重定向,否则我无法清理...所以,同样的问题。
我希望将脚本保存在一个打包的部分中,因此我宁愿避免使用单独的包装脚本或在通用 Windows 7+ 安装中不可用的任何内容。
有什么绝妙的想法或解决方法吗?
编辑:添加了初始解决方案的副本
我在此处添加了我改进的初始解决方案的副本(诚然,“hack”),它现在会自行清理,但仍有一些负面影响:
input = ""
stdin_is_tty = False
test_string_length = 5 ' arbitrary N (coder determined to minimize collision with possible inputs)
sendkey_string = ""
test_string = ""
for i = 1 to test_string_size
sendkey_string = sendkey_string & "{TAB}"
test_string = test_string & CHR(9)
next
sendkey_string = sendkey_string & "{ENTER}"
wsh.sendkeys sendkey_string ' send keyboard string signal to self
set stdin = WScript.StdIn
do while not stdin.AtEndOfStream
input = input & stdin.ReadLine
if input = test_string then
stdin_is_tty = True
else
input = input & stdin.ReadAll
end if
exit do
loop
stdin.Close
if not stdin_is_tty then
set stdin = fso.OpenTextFile( "CON:", 1 )
text = stdin.ReadLine
stdin.Close
end if
这个解决方案存在三个问题:
在命令行留下可见的痕迹(虽然现在,只是一个低可见性的空白行)
测试字符串(一组 N [编码器确定] TAB 后跟 NEWLINE)与任何重定向输入的第一行可能发生冲突,从而导致误报重定向确定。由于可以修改TAB的数量,因此编码器可以将这种可能性任意降低。
如果另一个窗口在执行
SendKeys部分之前获得焦点,则错误的窗口将接收代码字符串,从而导致错误的否定重定向确定。我估计这种情况发生的可能性很低。
【问题讨论】:
标签: vbscript stdin io-redirection