Stream 3 handle redirection causes output flood - windows

I was playing with wmic when this command
wmic<nul 3>nul
produced this:
The strange thing is, any command will work, but only stream 3 causes the output flood.
I googled and searched on SO "cmd output flood" and cannot find any duplicates nor any results.
Question: Why only stream 3 works?
Update: Likewise,
>con 3<con :
completely disables STDOUT!

I think that, as pointed by aschipfl, my answer to their question explains what the source of the problem is.
Please refer to them for the inner details, this answer is just a summary to explain the different behaviour.
When a redirection is created the code inside cmd handling this task tries to avoid problems saving the original handles to the streams that are being redirected so the redirection process can be reverted.
But the way the used function (standard _dup()) works and the order used when creating the redirection can alter the internal structures used in such a way that at the end the code reversing the redirection uses wrong information.
In short:
<nul 3<nul wmic
<nul saves the stdin handle in &3 and assigns nul stream to &0
3<nul saves the handle inside &3 into &4 and assigns nul stream to &3
wmic is executed. As it is reading from nul (assigned to &0) it can not read anything and ends.
&0 is restored from &3 where it was saved, BUT now &3 points to nul
&3 is restored from &4. Now it points to the original stdin
In the original aschipfl's question the observed behaviour was command prompt closing. After code execution
< file1 3< file2 echo/
the redirection cancel process leaves stdin stream pointing to a disk file (file2). cmd starts to read this file for commands to execute (as it normally does from stdin) and at end of file the read operation fails and the cmd instance ends. If you want a convoluted way of seeing it in work to start notepad you can try
( >file1 echo notepad ) & ( <nul 3<file1 break )
But in this question the behaviour is different because the stream assigned to &3, that will be copied to stdin once the redirection is reverted, is not a disk file but nul
<nul 3<nul echo/
Once the command is executed and redirections are reverted stdin stream is associated with nul device
cmd shows the prompt and tries to retrieve a new command reading from nul
The read operation ends but does not retrieve anything so cmd does not execute anything
goto 2
The question "Why only stream 3 works?" (in the sense of it does not work ;) ) is not correct. You can do something like
1>file1 <nul 4<nul echo/
and get the same result using different streams. Or you can do
3<nul <nul echo/
and it will work (in the sense of it works).
The order in which you request the redirection of the streams, how they are handled by cmd internal code and the existence of still active previous redirections can decide the success or failure of the command.

Related

Appearace of an extra character in command line after running a batch file

I want to run some diskpart commands from a text file and save its output to another text file.This is written in my batch file which i want to do it.
DISKPART /S E:\CMD.TXT > E:\OUT.TXT
PAUSE
and when I run it (even as administrator) it doesn't work well and this is written in the black screen of CMD:
DISKPART /S E:\CMD.TXT 1>E:\OUT.TXT
PAUSE
That extra 1 makes it not work correctly. whats that? and how can I solve it dear friends?
Windows supports a number of "standard devices"
0 is standard input (stdin) - normally assigned to the keyboard.
1 is standard output (stdout) - normally assigned to console
2 is standard error (stderr) - normally assigned to console
So, you could write a program which accepts input from stdin and writes results to stdout and errors to stderr (not all programs use stderr)
When you redirect input or output using redirectors (< and >) you can assign the input to a file if you wish, or direct output or errors likewise to a file.
The separate redirection of stdout and stderr is new to the NT-series of Windows (2K,XP,Vista,7,8,10) and > is assumed to mean stdout gets redirected. To redirect stdout explicitly you need to use 1>. To redirect stderr explicitly you need to use 2>.
Windows inserts the 1 to indicate that stdout is being redirected, but not stderr.
So - there's nothing amiss with what is being reported.
What is your command intended to do? COuld it be that windows is objecting to an attempt to create a file on E: when E: is the subject of a diskpart operation?

Piping in Windows cmd.exe doesn't forward standard output until the process completes?

Considering pipes in Windows command shell cmd.exe:
C:\>feed | filter
The standard output from the feeding process doesn't seem to reach the standard input of the filtering process until AFTER the feeding process runs to completion.
This type of 'buffering' can cause annoying delays in output messages for long running feeding processes (where you might want to hit 'ctrl-c' to interrupt it on early failure).
Is there a way to avoid this so that standard output from the feeding process reaches standard input on the filtering process as soon as data is available? (no buffering)
For example, the following simplified example:
feed.bat:
#echo off
echo something
sleep 3
echo something else
filter.bat:
#echo off
for /F "tokens=*" %%a in ('more') do (
echo _%%a
)
The below command doesn't display anything until after 3 seconds (when the sleep completes):
C:\>feed | filter
_something
_something else
The desired behavior would be that '_something' is printed, followed by a 3 second delay, followed by '_something else' being printed.
Pipes are asynchronous in Windows cmd.exe. They do not wait for the left side to complete before passing the info to the right. But your program does not demonstrate that for two reasons.
1) The FOR /F command does not begin iterating any rows until the command within the IN() clause completes. This is true for all FOR /F variants. The entire result of the IN() clause is buffered before any rows are iterated.
So your filter.bat couldn't possibly demonstrate the asynchronous nature of pipes.
2) The MORE command will not write partial lines - it waits until it receives a newline character before printing to stdout. (unless it reaches the end of file).
If you want to truly see the asynchronous nature of pipes, it is better to use a program that reads each character from stdin and immediately writes it back out to stdout.
Here is my version of FEED.BAT - it writes multiple lines with multiple pauses. It also writes three characters without linefeed with a pause after each one.
#echo off
echo something
timeout /nobreak 3 >nul
echo something else
timeout /nobreak 3 >nul
for /l %%N in (1 1 3) do (
<nul set /p "=%%N"
timeout /nobreak 3 >nul
)
echo(
echo Done
Here is my version of FILTER.JS - it reads one character from stdin and writes it out to stdout until it reaches the end of file.
while (!WScript.StdIn.AtEndOfStream) WScript.Stdout.Write(WScript.StdIn.Read(1));
And here is the command to test the behavior
feed | cscript //nologo filter.js
And here is the output, with <pause> inserted whenever there is a pause before more output.
something
<pause>something else
1<pause>2<pause>3<pause>
Done
My test above demonstrates that a pipe will immediately send any information it receives (assuming the filter is ready to receive it).
Design of the feeder and/or filter may mask the free flowing behavior. Your original test had a bottleneck in the filter in that it waited for all input before proceeding. It is also possible for the feeder to hold things up. Some programs have buffered output. The feeder may not send data until the buffer is full, or the buffer is flushed, or the stream closed.
There are a number of peculiar behaviors associated with Windows pipes. I recommend reading all the answers to Why does delayed expansion fail when inside a piped block of code? for a good overview of many non-intuitive issues.

pipe operator in batch script

Sorry if this is a duplicate question :-)
I got below line of code from a batch script. (script.bat)
echo %DATE% %TIME% some text ... >> %logfile% | c:\path\script1.bat >> %logfile%
What is the significance of pipe (|) symbol here?
The script.bat is working fine from command line (script.bat), and it is running script1.bat as well.
While running script.bat from scheduled task it intermittently failed to run script1.bat, exiting with errorlevel 1.
Anyone have any idea what this | doing here :-)
I'm assuming you know what pipes are normally used for. In your code, both sides of the pipe have their stdout redirected to a file. So the pipe is not fulfilling its normal purpose.
The way Windows implements pipes is to launch a new cmd thread for each side of the pipe.
In your case, the | is a quick and dirty way to instantiate parallel processing of the two commands.
Update
I just realized that both sides of the pipe are redirecting stdout to the same log file. That should never work, because only one cmd process (or thread) at a time can have the file open for write access. It certainly does not work for me from the command line. I get the following error: The process cannot access the file because it is being used by another process. The only way that does not fail is if logfile is set to nul.
If I had to guess, I think the original developer intended to use & instead of |. There is no reason to run a single ECHO statement in parallel with another batch script. It looks like the first statement is simply a timestamp.
I think your code should look like
echo %DATE% %TIME% some text ... >> %logfile% & call c:\path\script1.bat >> %logfile%
or better yet
>>%logfile% (
echo %DATE% %TIME% some text ...
call c:\path\script1.bat
)

Writing to file with batch

I'm trying to get a batch file to take user input and place it in a file... here is my code so far.
set /p input path=Path:
echo %path% >> log.txt
when I turn echo off, it's putting a "1" infront of the chevrons like so:
echo C:/Example/Path 1>> log.txt
the system can not find the file specified.
Please can anyone explain this
Certainly - I'll answer the question asked.
Originally, >somewhere or any redirection sent the data to the destination specified.
With the changes to the NT version, this was expanded. A digit DIRECTLY preceding a redirector means logical file number where 0=STDIN (standard-input) 1=STDOUT (standard output) and 2=STDERR (Standard error.) The others are undefined. This can cause problems where the data (typically) to be output ends with a digit, hence the >filename echo ... syntax
Consequently, for backward compatibility, (eg) >nul is still processed as it always has been, but it's ECHOed in its explict form 1>nul - sending STDOUT to nul to distinguish it from 2>somewhere_else
try this:
set /p "MyNewPath=Path: "
>>log.txt echo %MyNewPath%
Your SET statement is wrong. :-) Also, PATH is already assigned in the environment (the Windows PATH, and altering it may cause problems with running other commands in your batch file.
Try this instead:
set /p "Input=Path: "
echo %Input% >> log.txt

What does a forward slash before a pipe in cmd do to remove the line ending of an echo?

This code:
#echo off
echo/|set /p ="Executing backup...."
echo/|set /p =" backup procedure"
... came from Echoing in the same line and produces the below output in a cmd window:
Executing backup....backup procedure
However, I cant seem to find an explanation through google on what the forward slash does to the ¿pipe? to cause set's output to be echoed to the console / stdout
If anyone could also suggest a good website for learning more about cmd / cmd programs' features like this, it would be appreciated.
The echo/ is simply a way of printing only an empty line, instead of ECHO IS ON for a single echo.
But in this case it's completly unimportant, as the only use of the echo is for creating some stuff for the pipe, so the set /p will not wait for user input.
But this way to echo text without a linefeed is very inefficient, as a pipe creates two new instances of cmd.exe.
It's much simpler and faster to use
<nul set /p "=My Text"
The redirect from NUL will also stop the waiting for user input.
Care of https://stackoverflow.com/users/1201210/tenterhook
1) echo prints the result of set /p =... with or without the / before the pipe, so I'm not sure what your question is asking
2) (It will also print set /p =... with random junk after the echo, too, since it's reading the piped stuff and not the arguments it receives.)
I will hence suggest edits to the referenced SO post, to prevent others confusion.

Resources