Parrish Husband
Parrish Husband

Reputation: 3178

Is there a way to check for redirection inside a batch file?

If we have a batch file being redirected to a log like so:

C:\Testing\Example.bat > C:\Testing\Example.log

Is there any way inside the batch file to determine if there's a standard output redirect happening to a log file?

Basically the batch file I have requires three arguments passed to it. When arguments are left out, the batch file prints a usage example much like regular Windows commands would, and throws a 'pause' out so instructions can be read. However if the batch is called without arguments AND it's being logged, then the batch file will just sit there forever waiting for a key to break the pause, but won't show anything on the screen.

Normally this wouldn't be a problem at all, however I'm trying to make this idiot-proof since I won't be the one implementing the batch file in other scripts/scheduled tasks.

At this point it seems like I need to get rid of the usage pause entirely, but I was hoping for a solution where I wouldn't have to. Thanks for the help.

Upvotes: 4

Views: 1917

Answers (5)

jeb
jeb

Reputation: 82267

You could check if stdout is redirected with a small trick.
It uses the fact that outputting backspaces after a TAB moves the cursor back and if the cursor shall be moved before the home position in this situation, an error will be created to get a hint in your logfiles for the strange characters.

The drawback is, that it outputs <FF><TAB>><BACKSPACE><BACKSPACE><CR><LF> to stdout.
When stdout is the console, it simply clears it.
But when stdout is redirected to a file you append these characters to the file, but it can be commented with a meaningful text.

@echo off
setlocal
call :createTAB_BS

echo Script started, test for redirection:
cls
( echo %%TAB%%%%BS%%%%BS%%) | ( findstr "^"  2^> nul)
if %errorlevel% EQU 0 (
    >CON echo stdout is redirected
) ELSE (
    echo stdout goes to the console
)

exit /b

:createTAB_BS
for /f "tokens=1,2 delims=," %%A in ('forfiles /p "%~dp0." /m "%~nx0" /c "cmd /c echo(0x09,0x08"') do (
    set "TAB=%%A"
    set "BS=%%B"
)
exit /b

Upvotes: 1

dbenham
dbenham

Reputation: 130819

There is no good way to determine if stdin or stdout has been redirected using native batch commands.

But there is no need to worry about redirection in your case. Simply redirect the PAUSE stdin and stdout to con, and you don't have to worry about prior redirection.

pause <con >con

Update

It is possible to cleanly detect whether stdin and/or stdout and/or stderr has likely been redirected. But I haven't figured out a way to non-destructively determine which of those handles was redirected.

@echo off
2>nul (5>&4 break) && (
  >con echo There has been redirection
) || (
  >con echo No redirection found
)

The technique relies on the fact that whenever an existing handle is redirected, the old definition is saved in the lowest available undefined handle.

If there has not been any redirection, then 2>nul saves stderr in 3, and 4 is undefined. So 5>&4 fails, and the || branch is fired.

If there has been redirection, then 3 has already been defined to preserve the original value of the redirected handle, so 2>nul will save stderr in 4 (unless 4 has also already been used by some other redirection). Either way, the 5>&4 will succeed because 4 is defined, so the && branch will fire.

If the test reports that there has been redirection, then at least one of the following must be true:

  • stdin redirection
  • stdout redirection
  • stderr redirection
  • handle 4 defined directly with something like 4>"log.txt"
  • handle 5 defined directly with something like 5>"log.txt"

Unfortunately, I cannot determine which of the above are true, except for...

Over at DosTips, SiberiaMan has published a simple technique to determine if stdin has been redirected or is receiving a pipe:

2>nul >nul timeout /t 0 && (
  >con echo stdin not redirected or piped
) || (
  >con echo stdin has been redirected or is receiving piped input
)

Upvotes: 4

pieh-ejdsch
pieh-ejdsch

Reputation: 206

I think you just ask the wrong question. you want to find a way to end the batch with extra break when in cmd mode. and stop in batch mode without pausing. You can use CMDpause this will make a variable named cmdpause examples https://www.administrator.de/wissen/batchcode-erstellen-fehler-batch-leichter-finden-184736.html https://www.dostips.com/forum/viewtopic.php?t=7257#p47510

there is something from Dave and jeb. But I have no link.

Phil

Upvotes: 1

Daniel James
Daniel James

Reputation: 125

There isn't a way in standard Windows batch files (that I'm aware of) to determine where STDOUT is being redirected, or even if it is being redirected. However, you might wish to write your usage examples out to STDERR instead of STDOUT, so at least a simple redirect into a file will not capture the usage info.

Example test.cmd:

@ECHO OFF

ECHO Test output 1>&2
PAUSE 1>&2

Then call it:

test.cmd > output.log

Which will still output:

Test output
Press any key to continue . . .

Of course, this does nothing for when the file is called with STDERR being redirected.

test.cmd 2> error.log

Upvotes: 0

Nate Hekman
Nate Hekman

Reputation: 6657

I am not aware of any way to do this using only batch and standard commands. However, there are tricks that can be used from other languages such as native C or C# programs, if it's important enough to you to include another .exe along with your .bat.

Upvotes: 2

Related Questions