Continue capturing output after redirection - cmd

Okay, here's a toughie-- I'm capturing the output of cmd.exe just fine, reading from the pipe, yadda yadda yadda, but then a line in the cmd.exe batch file has the audacity to do:
dir err.txt >zz
.. that is, it's redirecting the output of the dir command, which is an internal command inside cmd.exe.
Problem is, this breaks my capturing of output! I can't get anything from cmd.exe after that point.
Apparently to redirect standard output, it closes it, or somehow breaks it, and makes a new stdout to redirect the output. And it never restores the old stdout handle.
Any ideas of how to track this output?

If you are allowed to modify the batch file, you may replace the inner redirection by a TEE command.
There are several ports to Windows (just google "windows command tee").
From Wikipedia:
In computing, tee is a command in various command-line interpreters (shells)
such as Unix shells, 4DOS/4NT and Windows PowerShell, which displays or pipes
the output of a command and copies it into a file or a variable

you should call dir err.txt in a separate process. try call dir err.txt >zz

Related

Why can't I redirect stdout/err of a program run by a batch file, called by another batch?

If I have this batch:
ScriptA.bat
someprog.exe
And this one:
ScriptB.bat
CALL ScriptA.bat
And I execute a command like:
ScriptB.bat > test.log
The output from someprog.exe is not logged. It flows through to the console. How can I avoid having to explicitly pipe the output of someprog.exe to a file, and instead just capture that from a higher level?
(Note I ultimately want to do this with a great many scripts launching assorted exes from inside those nesting, and I can't edit them all to redirect the output of each and every sub process they invoke).
I found the answer to this on another SO thread:
https://stackoverflow.com/a/11955380/3220983
As you'll see if reading the comments under the question, the problem I was encountering was that the messages I couldn't capture were not being piped to stdout or stderr at all! They were going straight to the console via something akin to a CON redirect from inside the specific executable I was trying to use.
The link I posted shows how to launch a PowerShell script from a batch script, which captures the entire console window contents, inclusive of CON output!

Piping not seem to work with cd | explorer in cmd

I've been learning batch scripting so I came across pipes and I/O redirection.
If this works:
tasklist | find "winword"
Why does this not:
cd | explorer
I expect this command to open explorer at current working directory as cd without any parameters outputs current directory and:
explorer %directory%
opens explorer at %directory%.
Is there something I am doing wrong here?
Open a Command Prompt window, type find "blah" and press Enter; you'll see it awaits user/keyboard/console input, which STDIN points to (press Ctrl+Z and Enter to end the prompt). Then type echo blah and press Enter; you'll notice the text blah is printed, so there is display/console output; this is pointed to by STDOUT. A pipe | takes the data at STDOUT from the left-side command and redirects it into STDIN for the right-side command.
Now type explorer into the Command Prompt window; of course an Explorer Window pops up, but what happens in the Command Prompt? right, nothing, it does not await any input at STDIN. So you can pipe to it but it will not care as it does not read at STDIN. In fact, GUI applications do generally not use STDIN and STDOUT, because these things are intended for command line applications.
Yet another example: in a Command Prompt window, type echo C:\Windows; quite obvious what will happen; then type echo C:\Windows| dir; what happens? dir returns the contents of the current directory but not of C:\Windows. Why? well, let's type dir first and see what happens: yes, dir shows the contents of the current directory, and it does not await console input; so at the right side of the pipe it receives data at STDIN but it simply doesn't care. You can try using dir "C:\some\other\folder", without and with the pipe, the output is just the same, STDIN is ignored here.
The echo/dir example also demonstrates the difference between console input (STDIN) and command line arguments or parameters: the path in the command line dir "C:\some\other\folder" is such an argument, and you cannot replace it by data from STDIN. To understand why, you need to distinguish between parse time (when the command is read and parsed by the interpreter) and run time (when the command is actually executed): arguments already have to be present at parse time, whilst STDIN is only relevant during run time, which is later. So we can say they just never meet.
This also reflects the situation with your attempt cd | explorer: the latter accepts command line arguments (which anyway need to be available before execution, so at parse time), but it doesn't care about STDIN. Also the STDOUT data from cd isn't available before execution (but only during run time), so it would arrive too late anyway...

Shell IO redirection order, pipe version

I have seen this question:
Shell redirection i/o order.
But I have another question. If this line fails to redirect stderr to file:
ls -xy 2>&1 1>file
Then why this line can redirect stderr to grep?
ls -xy 2>&1 | grep ls
I want to know how it is actually being run underneath.
It is said that 2>&1 redirects stderr to a copy of stdout. What does "a copy of stdout" mean? What is actually being copied?
The terminal registers itself (through the OS) for sending and receiving through the standard streams of the processes it creates, right? Does the other redirections go through the OS as well (I don't think so, as the terminal can handle this itself)?
The pipe redirection (connecting standard output of one command to the stdin of the next) happens before the redirection performed by the command.
That means by the time 2>&1 happens, the stdout of ls is already setup to connect to stdin of grep.
See the man page of bash:
Pipelines
The standard output of command is connected via a pipe to
thestandard input of command2. This connection is performed before
anyredirections specified by the command (see REDIRECTION below). If
|&is used, command's standard error, in addition to its
standardoutput, is connected to command2's standard input through the
pipe;it is shorthand for 2>&1 |. This implicit redirection of
thestandard error to the standard output is performed after
anyredirections specified by the command.
(emphasis mine).
Whereas in the former case (ls -xy 2>&1 1>file), nothing like that happens i.e. when 2>&1 is performed the stdout of ls is still connected to the terminal (and hasn't yet been redirected to the file).
That answers my first question. What about the others?
Well, your second question has already been answered in the comments. (What is being duplicated is a file descriptor).
As to your last question(s),
The terminal registers itself (through the OS) for sending and receiving through the standard streams of the processes it creates, right? Does the other redirections go through the OS as well (I don't think so, as the terminal can handle this itself)?
it is the shell which attaches the standard streams of the processes it creates (pipes first, then <>’s, as you have just learned). In the default case, it attaches them to its own streams, which might be attached to a tty, with which you can interact in a number of ways, usually a terminal emulation window, or a serial console, whatever. Terminal is a very ambiguous word.

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?

Is there a way to redirect stderror to stdout for the duration of a script in Windows?

As a long time UNIX shell scripter / release engineer coming into the Windows environment full time with my latest job, there are some things I inevitably miss.
One of them is my trusty old 'exec 2>&1' which in the Bourne shell permently knots together stderr and stdout for the duration of the script, so that logging will capture everything good and bad.
I realize you can append 2>foo.log to the end of every command line invocation, but I'm wondering if there's a better way.
Is there any equivalent in the Windows environment? We're using both .BAT file scripts and Perl scripts here (Mostly for build automation but also some other things) and I'd dearly love to know if this is possible at all.
In Perl you can do
open STDERR, '>&STDOUT' or die "Can't dup STDOUT";
to redirect the STDERR output of the script to STDOUT. See the open documentation for more info. I wouldn't expect this to effect the output of system calls, i.e. system or backticks.
You can nest the .BAT that does the real work inside a .BAT that redirects the streams for logging.
Something like
rem log.bat
cmd /c work.bat 1>>logfile.log 2>&1
rem work.bat
make all
perl cleanups.pl
might do the trick. You might be able to use CALL instead of directly invoking a second CMD.EXE, I haven't checked. If that does work, then the solution can be self contained: just call yourself with an extra argument to indicate the logging is in effect and with the streams redirected.
You can apply redirection to command blocks as well as single commands
(
echo 1
dir
echo 2
) >somefile.txt
Note that it is impossible to use labels and goto inside of command blocks, though.
Read this KB article from MS. Sample taken from the said article:
You can print the errors and standard output to a single file by using the "&1" command to redirect the output for STDERR to STDOUT and then sending the output from STDOUT to a file:
dir file.xxx 1> output.msg 2>&1
The 2>&1 thing seems to be working for me for scripts:
testcmd.cmd > stdboth.txt 2>&1
What exactly are you doing and what are you expecting when you're doing it?
:log_me
#if "%~1" NEQ "*" ("%~nx0" * >> "%~n0.log" 2>&1)
:script
echo this is success
echo this is error>&2
And, if your batch script has command line parameters:
:log_me
#call :script %* >> "%~n0.log" 2>&1
exit /b
:script
echo this is success
echo this is error>&2

Resources