4

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.

Ross Ridge
  • 38,414
  • 7
  • 81
  • 112
Parrish Husband
  • 3,148
  • 18
  • 40
  • Instead of using pause, you could use the choice command with a timeout. – rojo Mar 20 '13 at 21:16
  • 1
    It's possible to detect redirection and also if a pipe is active, [How to detect if input comes from pipe or redirected file](http://www.dostips.com/forum/viewtopic.php?p=10672#p10672). But you could also read this [Dostips:foolproof counting of arguments](http://www.dostips.com/forum/viewtopic.php?p=14612#p14612), how streams really works. – jeb Mar 20 '13 at 21:58
  • Jeb thanks for linking this documentation, it was certainly interesting to see what's actually happening with streams. Due to the complexity of setting up those examples though, I felt it would just complicate the batch file past the level I was comfortable with. I ended up just exiting the batch file if key parameters were missing, and linked the instruction label to [%1]==[/?] or [%1]==[help] – Parrish Husband Mar 22 '13 at 12:53

5 Answers5

4

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
)
Community
  • 1
  • 1
dbenham
  • 127,446
  • 28
  • 251
  • 390
  • This doesn't solve the problem of the pause happening when the batch file was redirected. The original goal was to try and have the pause only happen when it was opened directly. – Parrish Husband Sep 02 '18 at 18:45
  • 1
    I guess I misunderstood your goal. The con solution will display the pause message on the screen and wait for keyboard input properly, regardless of redirection. But if you want it to be fully automated without pause if there is redirection, then no, this does not solve the problem. – dbenham Sep 02 '18 at 19:05
  • Still cool, I'm logging away this approach if I ever need it in the future. I appreciate you giving a 5-year old question a shot. – Parrish Husband Sep 02 '18 at 19:07
2

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.

Community
  • 1
  • 1
Nate Hekman
  • 6,507
  • 27
  • 30
  • 1
    Thanks for the quick reply Nate. Comically enough I would have preferred doing this entirely in C#, and in fact most of the real work in the batch file is from an exe file I put together. However the project admins cried foul because they wanted something easily modifyable without needing to recompile. I'm on board with that concept, so my next stop was in fact powershell, which also got shot down because "we don't know what that is or how to use it". I can't seem to win one today... maybe if I really push for it they'll let me go Powershell, but for now I'm stuck with good old DOS. – Parrish Husband Mar 20 '13 at 21:03
1

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
jeb
  • 78,592
  • 17
  • 171
  • 225
1

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

pieh-ejdsch
  • 206
  • 1
  • 6
0

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
Daniel James
  • 125
  • 1
  • 8