gpt4 book ai didi

vbscript - 有什么方法可以检测 STDIN 是否已在 VBscript 中重定向?

转载 作者:行者123 更新时间:2023-12-02 19:38:41 27 4
gpt4 key购买 nike

我正在尝试在 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+

accepted answer对于 Q: "How to detect if Console.In (stdin) has been redirected?"展示了如何通过 P/Invoke 使用 Win32 调用来构建该结果(对于 NET 4.5 之前的 NET 版本)。但我不知道有什么方法可以将该方法转换为 VBscript。

我使用 SendKeys 构建了一个笨拙的部分解决方案,将流结束序列发送到脚本的键盘缓冲区中。但是,如果 STDIN 被重定向,解决方案会将 key 留在缓冲区中,除非我知道 STDIN 被重定向,否则我无法清理这些 key ...所以,同样的问题。

我更愿意将脚本保留在一个打包的片段中,因此我宁愿避免单独的包装脚本或通用 Windows 7+ 安装中不可用的任何内容。

有什么绝妙的想法或解决方法吗?

编辑:添加初始解决方案的副本

我在这里添加了改进的初始解决方案的副本(诚然,这是一个“黑客”),它现在可以自行清理,但仍然有一些负面影响:

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

该解决方案存在三个问题:

  1. 在命令行留下可见的痕迹(尽管现在只是一个可见性较低的空行)

  2. 测试字符串(一组 N 个[编码器确定的] TAB,后跟一个 NEWLINE)与任何重定向输入的第一行可能发生冲突,导致误报重定向确定。由于 TAB 的数量可以修改,因此编码器可以将这种可能性任意降低。

  3. 竞争条件,如果另一个窗口在执行 SendKeys 部分之前获得焦点,则错误的窗口将接收代码字符串,从而导致错误的否定重定向确定。我估计这种情况发生的可能性很低。

最佳答案

简而言之,不,但是......

我已经测试了我能想到的所有东西,但还没有找到合理的方法来做到这一点。

使用 WScript.StdInfso.GetStdStream 检索的 TextStream 包装器公开的属性/方法都没有提供足够的信息来确定输入是否被重定向/管道传输。

尝试从生成进程的行为/环境中获取信息(如何创建可执行文件是另一回事)也不太可能有用,因为

  • WshShell.Execute 始终生成进程,并重定向其输入和输出句柄

  • WshShell.Run 创建一个不继承当前进程句柄的新进程

  • Shell.Application.ShellExecuteWshShell.Run

  • 存在相同的问题

因此,这些方法都不允许生成的进程继承当前进程的句柄来检查它们是否被重定向。

使用 WMI 从正在运行的进程检索信息不会返回任何可用的内容(嗯,当存在重定向时,进程的 HandleCount 属性会有所不同,但它不可靠)

因此,无法从 vbs 代码确定是否存在重定向,剩下的选项是

  1. 不检测:如果管道输入必须存在,则在所有情况下都表现为 more 命令尝试找回它

  2. 指出:如果管道输入并不总是需要,请使用参数来确定是否需要读取标准输入流。

就我而言,我通常使用单个斜杠 / 作为参数(为了与某些也使用斜杠表示标准输入的 findstr 参数保持一致)。然后在vbs代码中

If WScript.Arguments.Named.Exists("") Then 
' here the stdin read part
End If
  • 检查之前:在启动脚本之前确定是否存在重定向。需要一个包装器 .cmd,但通过一些技巧,可以将两个文件(.cmd.vbs)合并为一个
  • 保存为.cmd

    <?xml : version="1.0" encoding="UTF-8" ?> ^<!------------------------- cmd ----
    @echo off
    setlocal enableextensions disabledelayedexpansion
    timeout 1 >nul 2>nul && set "arg=" || set "arg=/"
    endlocal & cscript //nologo "%~f0?.wsf" //job:mainJob %arg% %*
    exit /b
    ---------------------------------------------------------------------- wsf --->
    <package>
    <job id="mainJob">
    <script language="VBScript"><![CDATA[
    If WScript.Arguments.Named.Exists("") Then
    Do Until WScript.StdIn.AtEndOfStream
    WScript.StdOut.WriteLine WScript.StdIn.ReadLine
    Loop
    Else
    WScript.StdOut.WriteLine "Input is not redirected"
    End If
    ]]></script>
    </job>
    </package>

    它是存储在 .cmd 内的 .wsf 文件。批处理部分确定输入是否被重定向(timeout 命令无法获取重定向输入的控制台句柄)并将参数传递给脚本部分。

    然后,该过程可以被调用为

    < inputfile.txt scriptwrapper.cmd             input redirected
    type inputfile.txt | scriptwrapper.cmd input piped
    scriptwapper.cmd no redirection

    虽然这是一种方便的处理方法,但从 .cmd 调用 .wsf 部分虽然稳定并且工作没有问题,但依赖于脚本主机/cmd 组合的未记录行为。

    当然,您可以执行相同的操作,但使用两个单独的文件。不太干净,但行为已记录。

    关于vbscript - 有什么方法可以检测 STDIN 是否已在 VBscript 中重定向?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26683756/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com