findstr /g:/ not working reliable

Qlemo
Qlemo used Ask the Experts™
on
According to the help, findstr allows /g:/ for using a list provided via stdin for the search strings. However, I can get it to work only when using a file, either provided directly or via stdin redirection.

Example:
      @ > tmp.txt (echo a,b & echo c,d & echo e,f)
then:
      @(echo a&echo c)| findstr /g:/ tmp.txt
does not find anything, while
      @ > tmp.exc (echo a&echo c) & findstr /g:/ tmp.txt < tmp.exc
or
      @ > tmp.exc (echo a&echo c) & findstr /g:tmp.exc tmp.txt
or
      @ (echo a&echo b) & findstr /g:/ tmp.txt
work.
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
in the official help pages for FINDSTR, when including the /G: option, it's syntax is shown in the following form:

   /G:file

as far as i know, you cannot do the following:

   /G:/file

ie, you cannot insert an additional '/' (forward slash) character.


i'm not convinced you can have the following:

   >tmp.exc (echo a & echo c) & findstr /g:/tmp.txt <tmp.exc

please try it after first ensuring tmp.txt does not already exist. the same applies to the other example.


Commented:
looking at your last example:

   >tmp.txt (echo a,b & echo c,d & echo e,f)
   @(echo a&echo b) & findstr /g:/ tmp.txt

as it stands, this is both incorrect AND incomplete.

basically, this comprises of the following statements:

   >tmp.txt (echo a,b & echo c,d echo e,f)

   >con (echo a & echo b)
   findstr /g:/tmp.txt

of course, you'll still see 'a' and 'b' displayed on the screen because the two ECHO commands are independent from the FINDSTR command.

the FINDSTR /G: command has only one input file so FINDSTR hangs until you press CTR-C or CTRL-Z + ENTER.

the command:

   @(echo a & echo b) & findstr /g:/ tmp.txt

does not direct output from the ECHO statements to FINDSTR and this leaves me to believe you intended to type a '|' instead of a '&' as in the following:

   @(echo a & echo b) | findstr /g:/ tmp.txt

however, even this will fail because of the additional '/' therefore, assuming you meant:

   @(echo a & echo b) | findstr /g:tmp.txt

this will not work. simply because FINDSTR expects input from 2 files and although we normally regard input from a file or piped from another command or indeed redirected, to be the same, the inclusion of /G: changes FINDSTR's behaviour and forces it to expect input from 2 files.

the above code would be analogous to the following (using just one of the echos):

   findstr /g:tmp.txt "a"

as you can see, we're expecting a file, not a literal.


but in any case, this is wrong because the data you're intending to pipe in or redirect to FINDSTR is the file immediately following the /G: switch and this can't be done.

suppose you saved 'a' and 'b' to a file say, ab.txt as in:

   (echo a & echo b) >ab.txt

you could then do either of the following:

   FINDSTR /G:ab.txt tmp.txt

   FINDSTR /G:ab.txt <tmp.txt

   type tmp.txt | FINDSTR /G:ab.txt

ideally, it would br great if we could get the file 'ab.txt' using redirection or by using a pipe but, as stated above, it's just not possible because we can't separate the '/G:' from it's filename.

Commented:
interestingly, and after a little twiddling and antoher look at findstr's help page, i notice '/' is referred to as console.

this means you can do this:

   >tmp.txt (echo a,b & echo c,d & echo e,f)

followed by:

   findstr /g:/ tmp.txt

this has the effect of waiting for input from the keyboard. here, you would then type say, the letter 'd' and press the ENTER key. again, DOS waits for more input. to finish inputing data, you simply press CTRL-Z + ENTER at which point, DOS carries out the command.

this now leaves me to believe something like 'ECHO a |' will work as in:

   echo a | findstr /g:/ tmp.txt

by itself it does not work, as you quite rightly identified however, if you insert a CTRL-Z before the '|' it does, as in the following:

   echo a ^Z | findstr /g:/ tmp.txt

(the ^Z is produced by pressing CTRL-Z key combination) .......


Hmmmm.....Microsoft doesn't tell you this so, that's another one for the scrapbook of accidentally discovered DOS caveats.
Angular Fundamentals

Learn the fundamentals of Angular 2, a JavaScript framework for developing dynamic single page applications.

Commented:
by the way, this works too:

   >tmp.txt (echo a,b & echo c,d & echo e,f)

   >ss (echo a & echo f)

   type ss | findstr /g:/ tmp.txt


the output is:

   a,b
   e,f


no need for CTRL-Z in this case.

finally, this also works:

   findstr /g:/ tmp.txt <ss


to summarise then, the proper syntax is any one of the following:

   type search_strings.txt | findstr /g:/ file_to_search.txt

   findstr /g:/ file_to_search.txt <search_strings.txt


Commented:
okay, i'm revisiting due to further discoveries:

looking back at a previous question (comparing 2nd field with 1st field). my preference would be to use a list of strings coupled with FINDSTR /R /C:\<....\>.

interestingly enough (and I wonder if this was deliberate on Microsoft's part) if the list contains the following:

   \<abc\>
   \<def\>

then the simple FOR loop:

   for /f %a in (string_file) do echo %a

will output the following to the screen:

   \<abc\>
   \<def\>

now, that's interesting because we can now do the following:

   for /f %a in (string_file) do findstr /r /c:%a search_file

I hope this is making sense to you.


what would be interesting now is to do the same thing but without using the FOR loop

Qlemo"Batchelor", Developer and EE Topic Advisor
Top Expert 2015

Author

Commented:
Paul,

First comment:
I'm not using /G:/file but /G:/ file (extra space between slash and file). That is syntactically correct. It reads the search strings from "console", and searches in file. Hence the line you thought I had issued is wrong.

Second comment
The line
@(echo a&echo b) & findstr /g:/ tmp.txt
contains a typo, that is right. The first of your suggestions was correct (almost), it should have been
@(echo a& echo b) | findstr /g:/ tmp.txt
I had tried the correct version, and the result is wrong, only the first search string is applied. Again, look at the space between the slash and the file. The following stuff in that comment is not valid.

Third comment
Yes: /G:/ means "console" - whatever that should mean, as it is not CON: (hardcoded). Else you could never pipe. However, I guess it has somewhat special treatment, considering the EOF. I had it  somewhere in a thought that this might be the difference between echo and type (or redirecting from file). But you cannot echo an EOF, as the command interpreter will immediately stop as soon as it finds an EOF on commandline. And without, the result is completely undeterminable.

Fourth comment
The summary of your comment is what I have stated in my question: /G:  only works if the search strings are in a file.


In the last comment you lost the point. I might have said it not clear enough: I want the list of search strings coming from stdin, and no file may be involved as intermediate step. That this is not only not working, but completely errornous, can be proven by this command:
@ (echo x&echo y&echo.) | findstr  /g:/ tmp.txt
That should not echo anything, but does, and only the first two lines,  regardless of the file contents and the search strings ...

Commented:
Interesting.... have tried a few of these before in the past too. This got me for a while too.... and was about to post that method "X" did not work (as it didn;t the first time I tried it) and that method "Y" did but then I retry and find it works differently...

echo hello^Z| findstr /g:/ tmp.txt
proves the "control z finishes the line bit" I guess (though I'm sure I have had this work both ways!)

It seems that this works OK for one entry as long as there are no spaces around the pipe

echo a|findstr /g:/ tmp.txt

but that
(echo a)|findstr /g:/ tmp.txt

does not for me?!

And yes doing

(echo a&echo b&echo.) is just bizarre sending two lines of output.

I tried

echo a#c#e|findstr /g:/ tmp.txt

using dos edit to enter Control M or Contol J (CR / LF) in place of those # chars.  CR did nowt and LF just ended up seeing different lines.

(echo a
echo b
echo c) | findstr

worked the same as the & version.

It would be a very useful feature to have without the temp file so hoping one of you comes up with a workaround!

Steve
Qlemo"Batchelor", Developer and EE Topic Advisor
Top Expert 2015

Author

Commented:
> (echo a&echo b&echo.) is just bizarre sending two lines of output.

I just wanted the example to be as compact as possible :-D.
And you confirmed it does not make a difference whether I use the multi-line approach  - which looks much better, of course, but is a pain if used on commandline -  or the single line "echo cascade".

Commented:
As it seems the /g:/ input is treated as regular expressions, i.e.

echo [c-e]|findstr /g:/ tmp.txt

shows lines with c,d, or e in but
echo [c-e]|findstr /l /g:/ tmp.txt doesn't (though this does:)
echo c|findstr /l /g:/ tmp.txt

But I just can't make it read stdin sensibly beyond one line and can't work out a set of reasons why multiple lines in the search produce the results they do.

And.

echo [a-h]|findstr  /g:/ tmp.txt | more

on a file containing

A
B
...
H

returns only as far as G but

echo [A-H]|findstr  /g:/ tmp.txt | more
or
echo [a-h]|findstr  /i /g:/ tmp.txt | more

returns the whole lot.

Steve

Commented:
This does mean we can do

echo [A,E]|findstr /i /g:/ tmp.txt to find lines with a or e in but doesn't help when you want to supply them, one per line.

Commented:
I didn't mean > (echo a&echo b&echo.) is just bizarre sending two lines of output.
 was wrong... just that when I ran it against the file it seemed to only return two found lines regardless of what was searched for!
Qlemo"Batchelor", Developer and EE Topic Advisor
Top Expert 2015

Author

Commented:
See what bothered me? Hence I called that unreliable.
Maybe we should declare that as security issue with big impact, and MS has to fix it :-D

Commented:
And then we end up with a potentially fixe findstr on 10% of systems and broken ones on the others....

It has to be something to do with the way brackets / piping as you know the exact same line split into two with a file in the middle with standard redirects and it works as you'd expect.

Steve
Commented:
And same goes for

(for %%a in ("[a-c]" "[b-c]" "[1-9]") do echo %%a)|findstr /i /g:fi.txt tmp.txt
doesn't work but this does:

(for %%a in ("[a-c]" "[b-c]" "[1-9]") do echo %%a)>fi.txt
findstr /i /g:fi.txt tmp.txt

This does
for /f %%a in ("[a-c]") do echo %%a|findstr /i /g:/ tmp.txt

but this doesn't
(for /f %%a in ("[a-c]") do echo %%a)|findstr /i /g:/ tmp.txt

Commented:
qlemo..... just wondering.

How close are we to satisfying this question?

Is there anything I can add to bring this question closer to completion?

BTW where you say:

    @(echo a& echo b) | findstr /g:/ tmp.txt

have you tried the following:

   echo a & echo b| findstr /g:/ tmp.txt

NOTICE there is no space just prior to the pipe symbol.

Commented:
echo a & echo b| findstr /g:/ tmp.txt

will echo a to the screen and b through the pipe won't it, sure I tried that too!

It seems as soon as you have brackets to make a multi-line entry the pipe method breaks, even if you pass it through another program first, e.g. find or more etc.

So there may be NO answer that makes it work unless we stumble across some obscure method?

Steve
Commented:
BTW where you have file ABC:

   a,b
   c,d
   e,f


have you tried the following:

   for %a in (a c) do @echo %a| findstr /g:/ abc


the output is:

   a,b
   c,d


NOTE: there is no space just prior to the pipe symbol


But then, this is no different (output-wise) then where you have file AC

   a
   c


and you do this:

   findstr /g:/ abc <ac


or:

   type ac | findstr /g:/ abc

Commented:
That does work t0t0 and used that one myself... except it is doing a findstr command for each choice as opposed to one findstr using the whole list so if ordering is important for any reason it wouldn't work for instance, and for large files it would be searching multiple times (albeit mainly from cache I guess).

for %a in (1 7) do @echo %a| findstr /i /g:/ tmp.txt
1
1A
7
7G

And sadly this:

(for %a in (1 9) do @echo %a)| findstr /i /g:/ tmp.txt

doesn't give any output at all...

( I used an expanded tmp.txt as below for these tests as three lines isn't much good for proving anything when it seemed to randomly return two lines anyway).

I find it bizarre that if redirected a file into it using /g:/ and <findlist.txt or type findlist.txt | , pointing it at a file using /g:findlist.txt it works but the same content piped directly from echo statements does not work if more than one line....

Just compiled a little Qb45 program as follows which takes the command line input, replaces any # with LF and prints it back to STDOUT:

show$ = COMMAND$
hashpos = INSTR(show$, "#")

DO WHILE hashpos > 0
     MID$(show$, hashpos, 1) = CHR$(10)
     hashpos = INSTR(show$, "#")
LOOP

PRINT show$

that compiled as print.exe and redirected with

print 4#9#6|findstr /i /g:/ tmp.txt
worked producing:
4
6
9
4D
6F
9I

So piping does work from other programs, and from type but just does not work from multiple lines of echo combined.
Steve
1
2
3
4
5
6
7
8
9
0
1A
2B
3C
4D
5E
6F
7G
8H
9I
0J

Open in new window

Commented:
Ahhh..

cmd /a /c (echo 4^&echo 9)|findstr /g:/ tmp.txt

works.
but

cmd /c (echo 4^&echo 9)|findstr /g:/ tmp.txt

doesn't

So I summise that it is a unicode issue and that echo by default outputs unicode text?

Steve
Qlemo"Batchelor", Developer and EE Topic Advisor
Top Expert 2015

Author

Commented:
You might be on something. But

cmd /a /c (echo 4^&echo 9)^|findstr /g:/ tmp.txt
doesn't work, too.

Commented:
Agreed.

cmd /a to start new non-unicode cmd. prompt:
(echo 4& echo 9)|findstr /i /g:/ tmp.txt

doesn't either ..
Commented:
dragon-it

   for %a in (1 7) do @echo %a| findstr /i /g:/ tmp.txt

works perfectly well for what it's purpose is....


   (for %a in (1 9) do @echo %a)| findstr /i /g:/ tmp.txt

doesn't give any output (as you already stated) but in my comment above i wrote:

   for %a in (1 9) do @echo %a| findstr /i /g:/ tmp.txt

(without the brackets) which DOES give the correct output


Commented:
WOW !! the CMD approach is CLOSE !!!
Qlemo"Batchelor", Developer and EE Topic Advisor
Top Expert 2015

Author

Commented:
If I use external programs, like ctext.exe, to produce the output it works. Similar to the QB45 sample above. You can use brackets, pipe, multiline commands, and do whatever you like - it works. So maybe the echo is indeed the culprit, not findstr?!

Commented:
Can't remember why we catually started this mind... since there are other options available... but it must have it's uses ...

Anyway wife gone into labour so better not be on the computer :-)

Steve

Commented:
wow....

   CMD /A /C (ECHO dragon-it) | FINDSTR /g:/ wife

ouput =

   baby!!

Commented:
It does work with other apps though so I guess it is a combination:

(echo a&echo ca&echo d&echo cb)|find "c"
c
cb

Commented:
haha off now.

Commented:
don't forget your beathing exercises.... !! good luck DAD!

Commented:
please review two new DOS commands: pushb (as opposed to pushd) and popb.


   PUSHB wife

followed by....

   POPB

output=

   baby

Commented:
haha, I wouldn't suggest saying "POP" in the hearing of someone in labour...they seem to think it is more effort than that...
Qlemo"Batchelor", Developer and EE Topic Advisor
Top Expert 2015

Author

Commented:
Guys,

I reckon I should close this question, as we cannot expect further insight. However, I do not know how I should award points here at all.
  1. My introducing examples were partitally false - a typo, but an important one.
  2. We do not have any solution or somehting near that. I assume the "'You can't do that'  is a valid answer" case applies here.
I'm open for suggestions.

Commented:
50:50 amongst contributors seems fair... agreed don't think there IS an answer as such.  Lots of workaround and bodges which end up harder to use than other alternatives.

Commented:
I thought we flogged this one to death....

I also thought hidden among all the comments, there were fragments of the answer scattered about but I'll need to give it another look to confirm.

Just giving it another look....

Commented:
Okay, as far as I understand it, your question evolves around the following:

   (echo a & echo c) | findstr /g:/ abcdef.txt

ABCDEF.TXT contains the following three text lines:

   a,b
   c,d
   e,f

The expected output is:

   a,b
   c,d

The /G:/ switch tells FINDSTR to get it's search string/s from the console.

This can be done as the following screen dump shows:

   C:>findstr /g:/ abcdef.txt
   a
   b
   ^Z
   a,b
   a,c

   C:>

As you can see, typing FINDSTR /G:/ at the DOS prompt, DOS waits for further input. You should be familiar with the a, b and ^Z - each letter a and b are entered via the keyboard ending with a CTRL-Z. FINDSTR immediately correctly displays a,b and c,d.

You seem to suggest DOS commands treats anything inside parenthesis as a stream.

Here's an example of a stream sent to a file:

   (for /l %%a in (1,1,5) do echo %%a)>12345.txt

The contents of 12345.TXT is:

   1
   2
   3
   4
   5

Another way this can be achieved is in the following:

   (echo 1 & echo 2 & echo 3)>123.txt

And this would indeed work as can be seen in 123.TXT

   1
   2
   3

After spending quite a lot of time trying different approaches, I'm going to conclude:

It would be a matter of course to do the following:

   echo a>ac.txt
   echo c>>ac.txt
   findstr /g:ac.txt abcdef.txt


Anyway, now for the best part.... let's press on and share some points among us.... hehehe...

Commented:
oops! it was supposed to be:

   C:>findstr /g:/ abcdef.txt
   a
   c
   ^Z
   a,b
   d,d


(that's what can happen when you manually edit stuff - it turns to pulp)

Commented:
hahaha.... i don't believe it. The c changed to a d when i rush-edited it....

   C:>findstr /g:/ abcdef.txt
   a
   c
   ^Z
   a,b
   c,d
Commented:
I think the point was to do it without a temp file, otherwise you can do it with the /g: option pointing at the file anyway.
If you do
(echo a & echo b)>x.txt
type x.txt |findstr /g:/ etc.
it works
but
(echo a & echo b) |findstr /g:/ etc.
doesn;t.
Steve
"Batchelor", Developer and EE Topic Advisor
Top Expert 2015
Commented:
Exactly. The point is not to use a temp file for the /g: option. Instead, the list with (regular) search expressions should be generated by echo.
The bonus question was to explain why it does not work ;-)

Commented:
I do understand all that...

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial