首页 文章

抑制命令行输出

提问于
浏览
104

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

echo off

taskkill /im "test.exe" /f > nul

pause

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

ERROR: The process "test.exe" not found.

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

如何抑制输出?

4 回答

  • 187

    因为错误消息经常转到 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之间存在细微的差别 .

    Update: 我知道OP了解"file"的特殊性 NUL I 'm writing to here, but a commenter didn' t所以让我在这方面稍微详细一点 .

    一直追溯到最早的MSDOS版本,某些文件名被文件系统内核抢占并用于引用设备 . 这些名称的最早列表包括 NULPRNCONAUXCOM1COM4 . NUL 是空设备 . 它总是可以打开读取或写入,任何数量都可以写在上面,读取总是成功但不返回任何数据 . 其他包括并行打印机端口,控制台和最多四个串行端口 . 从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将既有用又令人生畏 . 规则要比它们应该的复杂得多,实际上不可能回答一些简单的问题,如"how long is the longest legal fully qualified path name?" .

  • 6

    请改用此脚本:

    @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 .

    @pause

    显示暂停消息 Press any key to continue . . . ,直到有人按下某个键 .

    注意: @ 符号隐藏了每个命令的提示 . 这种方式最多可以保存8个字节 .

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

  • 0

    mysqldump不能用于: >nul 2>&1
    而是使用: 2> nul
    这会抑制stderr消息:"Warning: Using a password on the command line interface can be insecure"

  • 1

    您也可以这样做:

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

相关问题