如何检测 Console.In (stdin) 是不是已被重定向?

Posted

技术标签:

【中文标题】如何检测 Console.In (stdin) 是不是已被重定向?【英文标题】:How to detect if Console.In (stdin) has been redirected?如何检测 Console.In (stdin) 是否已被重定向? 【发布时间】:2011-03-28 01:30:30 【问题描述】:

我想编写一个具有不同行为的控制台应用程序,具体取决于输入是来自键盘还是来自文件。

有可能吗?在 C# 中最优雅的方式是什么?

【问题讨论】:

【参考方案1】:

您可以通过 p/调用 Windows FileType() API 函数来查找。这是一个帮助类:

using System;
using System.Runtime.InteropServices;

public static class ConsoleEx 
    public static bool IsOutputRedirected 
        get  return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdout)); 
    
    public static bool IsInputRedirected 
        get  return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stdin)); 
    
    public static bool IsErrorRedirected 
        get  return FileType.Char != GetFileType(GetStdHandle(StdHandle.Stderr)); 
    

    // P/Invoke:
    private enum FileType  Unknown, Disk, Char, Pipe ;
    private enum StdHandle  Stdin = -10, Stdout = -11, Stderr = -12 ;
    [DllImport("kernel32.dll")]
    private static extern FileType GetFileType(IntPtr hdl);
    [DllImport("kernel32.dll")]
    private static extern IntPtr GetStdHandle(StdHandle std);

用法:

bool inputRedirected = ConsoleEx.IsInputRedirected;

更新:这些方法已添加到 .NET 4.5 的 Console 类中。如果没有归属,我可能会添加:(只需使用相应的方法而不是这个帮助类。

https://msdn.microsoft.com/en-us/library/system.console.isoutputredirected.aspx https://msdn.microsoft.com/en-us/library/system.console.isinputredirected.aspx https://msdn.microsoft.com/en-us/library/system.console.iserrorredirected.aspx

【讨论】:

上面的代码适用于 .NET 4.5,现在包括属性 IsErrorRedirected、IsInputRedirected 和 IsOutputRedirected。 有趣的实现,可惜不适用于跨平台开发。 isatty() 函数往往可以在其他平台上进行类似的测试。【参考方案2】:

有趣的是,当管道打开时,System.Console.WindowHeightSystem.Console.WindowWidth 参数是,我发现这是由于代码路径中的几个ArgumentOutOfRangeException 不关心控制台大小为零。

跨平台:在 Linux 和 Windows 上 MS dotNETMono 下的行为是相同的(我没有在 Mac 上尝试过)。

当使用管道传输 STDIN 或 STDOUT 时,控制台大小设置为 0。因此基于 Hans 的实现,我的代码如下:

using System;


 public static class ConsoleEx 
        public static bool IsConsoleSizeZero 
            get 
                try 
                    return (0 == (Console.WindowHeight + Console.WindowWidth));
                
                catch (Exception exc)
                    return true;
                
            
        
        public static bool IsOutputRedirected 
            get  return IsConsoleSizeZero && !Console.KeyAvailable; 
        
        public static bool IsInputRedirected 
            get  return IsConsoleSizeZero && Console.KeyAvailable; 
        

2016 年更新: 向IsConsoleSizeZero 代码添加了异常处理,以提高代码在更广泛的上下文中的可用性。

代码似乎仍然运行良好,至少从使用 MonoDevelop / Xamarin Studio 的经验来看。

相关

MSDN:KeyAvailable

Setting System.Console.WindowHeight throws an System.NotSupportedException under Mono.

【讨论】:

Console.WindowHeight 不错!不过,我不太确定Console.KeyAvailable 的使用。一方面,完全可以同时重定向输入和输出,而您的代码将无法检测到这一点。 我在 Debian Wheezy 上运行。 0 == (Console.WindowHeight + Console.WindowWidth) 技巧对我有用。例如,当我的应用程序通过 monit 启动时,总​​和为 0。当从命令提示符手动启动时,它是一个正数。无控制台运行时,KeyAvailable 返回 false,但如果我实际调用 ReadKey,则返回零。 我可以确认这似乎适用于 Mac。虽然 Mono 在 Xamarin Studio 中报告“警告:Mono LIMITATION: Only works on windows”。我不知道“Windows”是否拼写错误(大写 W),或者错误是说它在调试器中不起作用。 这段代码不安全,Console.KeyAvailable 在某些情况下当输入被重定向时会抛出 InvalidOperationException —— 所以仅仅检查该属性可能会使应用程序崩溃【参考方案3】:

Lorenz 的回答是一个好的开始,可惜只能作为一个灵感。运行控制台应用程序的模式更多。

    标准运行(在控制台中,没有任何重定向)

    在控制台中一切正常。

    使用标准输入和/或标准输出重定向从控制台执行重定向

    例如

    type input_file.txt | application.exe(在 Windows 中),或 application.exe <input_file.txt 用于输入重定向

    (在 Linux 中将 type 替换为 cat

    application.exe | grep patternapplication.exe >output_file.txt 用于输出重定向

    type input_file.txt | application.exe | grep patternapplication.exe <input_file.txt >output_file.txt 用于输入和输出重定向

    从带有标准输出的控制台重定向执行错误输出重定向

    例如application.exe >output_file.txt 2>error_file.txt

    使用隐藏控制台执行并重定向输入/输出/错误

    例如来自 GUI 应用程序(控制台根本不可见)

    使用隐藏控制台执行没有输入/输出/错误重定向

每种模式都有自己的“功能”。 Console.WindowHeightConsole.WindowWidthWindows 中以标准方式用于第一和第二模式。在 Linux 中,第 2 和第 3 模式的返回值是 0。因此,在 Linux 中,您不能仅检测输入重定向。

因此,Lorenz answer 中的代码不能在所有情况下都用于检测重定向。读取Console.WindowHeightConsole.WindowWidth 时的IOException 仅在(例如第3 模式)无输出 且仅适用于 时抛出>Windows

要检测输入重定向(仅在Windows中)使用这个函数:

private static bool IsInputRedirected()

  try
  
    if (Console.KeyAvailable)
    
      return (false);
    
  
  catch (InvalidOperationException)
  
    return (true);
  
  return (false);

对于所有其他重定向和操作系统...尝试尝试如何检测它们。不同的控制台属性和函数'工作'(抛出异常,或零返回值)用于不同的模式。

Windows 7 .NET Framework 4 Client ProfileMono JIT compiler version 4.2.1 (Debian 4.2.1.102+dfsg2-7ubuntu4) 上测试。

重要提示:

不要在 Linux 中使用此功能进行输入重定向(检测正在运行的操作系统/平台,例如 Windows 的 Mono),因为当您错误地期望重定向并且重定向未激活时,它可能会导致更多麻烦.

【讨论】:

这是迄今为止唯一对我有用的解决方案。 .NET Core 3.1 使用 C#。谢谢!【参考方案4】:

由于框架 4.5 存在属性 Console.IsInputRedirected。 8-)

请参阅 Microsoft Docs:https://docs.microsoft.com/en-us/dotnet/api/system.console.isinputredirected

【讨论】:

也适用于 .NET 5 和 6,这非常好。谢谢!

以上是关于如何检测 Console.In (stdin) 是不是已被重定向?的主要内容,如果未能解决你的问题,请参考以下文章

如何在C中检查stdin是不是为空

你遇到过VMware Remote Console Plug-in安装问题??

如何中止在 python3 中等待 sys.stdin?

将stdin设置为C中的文件时如何从键盘读取

如何将数据写入stdin以供等待stdin输入的单独线程使用?

如何确定输入(stdin)是不是损坏?