4

When having a text file test.txt containing this1:

test
data

The following code returns the content of the text file with the first character removed:

< "test.txt" (
    > nul pause
    findstr "^"
)

The same happens when using a pipe:

type "test.txt" | (
    > nul pause
    findstr "^"
)

Because the pause command takes exactly one character.

However, when replacing the pause command by either of the following commands, the output is empty, although – like pause – they prompt (/W) for a single character only:

  • 2> nul xcopy /W ? .
  • replace /W /U ? .

Why is this, what happens here?
Are xcopy /W and replace /W consuming all redirected/piped text data, even multiple lines, although they display only the first character they receive? Are they messing around with the file pointer?
Is there a way to prevent these commands from absorbing more than a single character?


1… With the last line terminated by a line-break in order for findstr not to hang indefinitely – see this thread: What are the undocumented features and limitations of the Windows FINDSTR command?, section »FINDSTR hangs on XP and Windows 7 if redirected input does not end with <LF>«.

aschipfl
  • 33,626
  • 12
  • 54
  • 99

1 Answers1

2

The behavior actually varies a bit between redirection vs a pipe.

Redirection

It appears that XCOPY and REPLACE simply move the stdin file pointer to End-Of-File (EOF).

If you use FIND /V "" instead of FINDSTR "^", then you get the entire file as output because FIND resets the file pointer to the beginning of the file upon startup. So the stdin stream is still valid after XCOPY runs, but the file pointer is at EOF.

XCOPY must be moving the file pointer without actually reading all of the data because when I use big.txt containing 0.5 GBytes, it is still "instantaneous". There would be a significant delay if XCOPY had to read all of the file before it proceeded.

Pipes

I don't fully understand the implications of this, but I believe the standard pipe is block buffered. XCOPY and REPLACE read up to 1 full block before they continue, leaving the remainder of the piped data for FINDSTR to read.

I piped in a 127 line file containing 4191 bytes, and FINDSTR output 97 bytes over 3 lines. So in this case XCOPY appears to read 4094 bytes.

I then piped in a 5000 byte file without any new lines and FINDSTR output 908 bytes, meaning XCOPY appears to read 4092 bytes.

So the pipe block buffer must be somewhere in the neighborhood of 4 kbytes. My guess is XCOPY simply moves the file pointer to the end of the current buffer without reading all of the data, but I don't know how to test that.

As would be expected, substituting FIND for FINDSTR does not change the result when using pipes - there is no way to reset the file pointer back to the beginning of the piped data after it has already been read.


I can't imagine that there is any way to modify the behavior of XCOPY or REPLACE... it is what it is.

As for why XCOPY and REPLACE behave the way they do?... I haven't a clue. The Microsoft "batch" world is so idiosyncratic that I gave up asking why long ago.

Community
  • 1
  • 1
dbenham
  • 127,446
  • 28
  • 251
  • 390