【问题标题】:Suppress command line output禁止命令行输出
【发布时间】:2010-11-18 18:16:59
【问题描述】:

我有一个像这样的简单批处理文件:

回声 taskkill /im "test.exe" /f > nul 暂停

如果“test.exe”没有运行,我会收到以下消息:

错误:找不到进程“test.exe”。

即使我已将输出重定向到 NUL,为什么仍会显示此错误消息?

如何抑制该输出?

【问题讨论】:

    标签: batch-file


    【解决方案1】:

    因为错误消息经常发送到stderr 而不是stdout

    将调用更改为:

    taskkill /im "test.exe" /f >nul 2>&1
    

    一切都会好起来的。

    这是因为stdout 是文件描述符1,而stderr 是文件描述符2 按照惯例。 (顺便说一下,0 是 stdin。)2>&1 从新值 1 复制输出文件描述符 2,该值刚刚被重定向到空设备。

    这种语法(粗略地)从许多 Unix shell 中借用,但您必须小心,因为 shell 语法和 CMD.EXE 之间存在细微差别。

    更新:我知道 OP 了解我正在写信给这里的名为 NUL 的“文件”的特殊性质,但评论者没有,所以让我离题一点这方面的更多细节。

    一直追溯到最早的 MSDOS 版本,某些文件名被文件系统内核抢占并用于引用设备。这些名称的最早列表包括NULPRNCONAUXCOM1COM4NUL 是空设备。它始终可以打开以进行读取或写入,可以在其上写入任意数量,并且读取始终成功但不返回任何数据。其他包括并行打印机端口、控制台和最多四个串行端口。从 MSDOS 5 开始,还有几个保留名称,但基本约定非常完善。

    在创建 Windows 时,它最初是作为 MSDOS 内核之上的一个相当薄的应用程序切换层,因此具有相同的文件名限制。当 Windows NT 被创建为一个真正的操作系统时,NULCOM1 这样的名称被广泛认为无法消除它们。但是,新设备总是会获得会阻止未来用户使用这些名称来获取实际文件的名称的想法显然是不合理的。

    Windows NT 和随后的所有版本(2K、XP、7 和现在的 8)都使用从内核代码到精心构造且高度不可移植的用户空间代码的更精细的NT Namespace。在该命名空间中,设备驱动程序通过\Device 文件夹可见。为了支持所需的向后兼容性,有一种特殊的机制使用\DosDevices 文件夹,它实现了任何文件系统文件夹中的保留文件名列表。用户代码可以使用通常 Win32 API 下方的 API 层浏览这个内部名称空间;探索内核命名空间的好工具是来自 Microsoft SysInternals 小组的WinObj

    有关 Windows 中文件(和设备)合法名称规则的完整描述,this page at MSDN 将提供丰富的信息和令人生畏的信息。规则比应有的复杂很多,实际上不可能回答一些简单的问题,例如“最长的合法完全限定路径名有多长?”。

    【讨论】:

    • 感谢您的回答,最重要的是您的解释。
    • 推荐:taskkill /im "test.exe" /f >%temp%\nul 2>&1 & del %temp%\nul。这将防止将空白的空文件放置到本地目录中
    • @SamyBencherif, NUL 是保留文件名,映射到 NUL 设备。您不能在任何目录中创建名为 NUL 的实际文件。
    • 在 powershell 中失败并出现错误 FileStream was asked to open a device that was not a file. For support for devices like 'com1:' or | 'lpt1:', call CreateFile, then use the FileStream constructors that take an OS handle as an IntPtr.
    • @jjxtra 发现对于 powershell,你必须像这样使用它:>$null 2>&1
    【解决方案2】:

    你也可以这样做:

    tasklist | find /I "test.exe" > nul && taskkill /f /im test.exe > nul
    

    【讨论】:

    • 尽管问题的上下文是批处理脚本,但我发现在 PowerShell 中,上述语法因“out-file : FileStream 被要求打开一个不是文件的设备而失败。寻求支持对于像 'com1:' 或 'lpt1:' 这样的设备,调用 CreateFile,然后使用将 OS 句柄作为 IntPtr 的 FileStream 构造函数。" 解决方案是将 > nul 替换为 >$null。跨度>
    【解决方案3】:

    mysqldump 不适用于:>nul 2>&1
    改为使用:2> nul
    这会抑制 stderr 消息:“警告:在命令行界面上使用密码可能不安全”

    【讨论】:

      【解决方案4】:

      改用这个脚本:

      @taskkill/f /im test.exe >nul 2>&1
      @pause
      

      2>&1 部分的实际作用是将stderr 输出重定向到stdout。我将在下面更好地解释它:

      @taskkill/f /im test.exe >nul 2>&1

      杀死任务“test.exe”。将stderr 重定向到stdout。然后,将stdout 重定向到nul

      @暂停

      在有人按键之前显示暂停消息Press any key to continue . . .

      注意:@ 符号隐藏了每个命令的提示。通过这种方式,您最多可以节省 8 个字节。

      脚本的最短版本可能是:
      @taskkill/f /im test.exe >nul 2>&1&pause
      & 字符第一次用于重定向,第二次用于分隔命令。
      一行中不需要两次 @ 字符。尽管您发布的代码是 49 字节,但此代码只有 40 字节!我实际上节省了 9 个字节。如需更简洁的代码,请查看上方。

      【讨论】:

      • 是的,我知道帖子的一半实际上是如何缩短您的代码。
      猜你喜欢
      • 1970-01-01
      • 2013-05-20
      • 2013-05-23
      • 2011-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-01
      相关资源
      最近更新 更多