How to Detect If Console.In (Stdin) Has Been Redirected

How to detect if Console.In (stdin) has been redirected?

You can find out by p/invoking the Windows FileType() API function. Here's a helper class:

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);
}

Usage:

bool inputRedirected = ConsoleEx.IsInputRedirected;

UPDATE: these methods were added to the Console class in .NET 4.5. Without attribution I might add :( Simply use the corresponding method instead of this helper class.

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

Is there any method to detect whether STDIN has been redirected within VBscript?

In short, no, but ...

I've tested everything i could think of and have not found a reasonable way to do it.

None of the properties/methods exposed by the TextStream wrappers retrieved with WScript.StdIn or fso.GetStdStream give enough information to determine if the input is redirected/piped.

Trying to obtain information from the behaviour/environment of a spawned process (how to create the executable is other story) is also unlikely to be useful because

  • WshShell.Execute always spawns the process with its input and output handles redirected

  • WshShell.Run creates a new process that does not inherit the handles of the current one

  • Shell.Application.ShellExecute has the same problem as WshShell.Run

So, none of these methods allow the spawned process to inherit the handles of the current process to check if they are redirected or not.

Using WMI to retrieve information from the running process does not return anything usable (well, HandleCount property for the process differs when there is a redirection, but it is not reliable)

So, not being able to determine from vbs code if there is a redirection, the remaining options are

  1. Don't detect it: If the piped input must be present, behave as the more command and in all cases try to retrieve it

  2. Indicate it: If the pipe input is not always required, use an argument to determine if the stdin stream needs to be read.

In my case, I usually use a single slash / as argument (for coherence with some of the findstr arguments that also use a slash to indicate stdin input). Then in the vbs code

If WScript.Arguments.Named.Exists("") Then 
' here the stdin read part
End If

  1. Check before: Determine if there is redirection before starting the script. A wrapper .cmd is needed, but with some tricks both files (.cmd and .vbs) can be combined into one

To be saved as .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>

It is a .wsf file stored inside a .cmd. The batch part determines if the input is redirected (timeout command fails to get a console handle on redirected input) and pass the argument to the script part.

Then, the process can be invoked as

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

While this is a convenient way to handle it, the invocation of the .wsf part from the .cmd, while being stable and working without problems, relies in an undocumented behaviour of the script host / cmd combination.

Of course you can do the same but with two separate files. Not as clean, but the behaviour is documented.

How can I determine whether Console.Out has been redirected to a file?

p/invoke GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)), or call an innocuous console function like GetConsoleScreenBufferInfo to check for invalid handle error. If you want to know about standard error, use STD_ERROR_HANDLE. I believe you can even compare handles returned by GetStdHandle(STD_OUTPUT_HANDLE) and GetStdHandle(STD_ERROR_HANDLE) to detect stuff like 2>&1.

How do I detect if stdin or stdout is redirected in FreePascal under Windows?

Use

GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));

for stdout. It should be obvious what to do for stdin.

How do I determine if sys.stdin is redirected from a file vs. piped from another process?

You're looking for stat macros:

import os, stat

mode = os.fstat(0).st_mode
if stat.S_ISFIFO(mode):
print "stdin is piped"
elif stat.S_ISREG(mode):
print "stdin is redirected"
else:
print "stdin is terminal"

Detect redirect standard output to nul

The function you quote, originally by Hans Passant, was added to the console in .NET 4.5 (see Console.IsOutputRedirected et al)

Interestingly enough, the implementation in .NET is capable of detecting a redirect to NUL. It does this by doing an additional check whenever the FileType check yields false:

int mode;
bool success = Win32Native.GetConsoleMode(ioHandle, out mode);
return !success;

If you are on .NET 4.5, simply use the built-in function. If not, duplicating this extra check should solve your problem.

How do I check if my Delphi console app is redirected to a file or pipe?

you can use the GetStdHandle and GetFileType functions.

first you retrieve the console output handle using the GetStdHandle function and then you can check the type of the handle with the GetFileType function.

{$APPTYPE CONSOLE}

{$R *.res}

uses
Windows,
SysUtils;


function ConsoleRedirected: Boolean;
var
FileType : DWORD;
begin
FileType:= GetFileType(GetStdHandle(STD_OUTPUT_HANDLE));
Result := (FileType=FILE_TYPE_PIPE) or (FileType=FILE_TYPE_DISK);
end;


begin
try
if ConsoleRedirected then
Writeln('Hello From File')
else
Writeln('Hello Console');
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
end.

How to know if std::cin is from redirect?

This answer is based on @JoachimPileborg comment

#include <io.h>
#include <stdio.h>
bool isInputRedirected()
{
return (!(_isatty(_fileno(stdin))))
}

Original source in MSDN

How to tell if stderr has been redirected in Windows?

  1. Call GetStdHandle to get the stderr handle.
  2. Pass that handle to GetFileType to find out what type of file it is.
  3. If that returns FILE_TYPE_CHAR then stderr could be a console, but call GetConsoleMode to check.
  4. If GetConsoleMode fails then stderr has been redirected to another character device, such as a printer.


Related Topics



Leave a reply



Submit