I'm piping output from a command to findstr to extract certain lines. Here's my code:
example_command.exe | findstr /C:"string_D " /C:"string_B " /C:"string_C " /C:"string_A "
Yes, there are two spaces after the string text. I expected the output to be:
string_D
string_B
string_C
string_A
However, I'm getting:
string_A
string_B
string_C
string_D
findstr appears to be sorting the output alphabetically. Can that be disabled? I'd like it to output in the same order I entered it.
I want to do this with standard Windows 7 commands so I can easily distribute it in batch files.
I can separate the strings and run example_command.exe four times but that takes four times as long.
Is this another undocumented feature of findstr?
While it's pretty much running example_command.exe multiple times, this should give you the output you're looking for.
example_command.exe | findstr /C:"string_D " && example_command.exe | findstr /C:"string_B " && example_command.exe | findstr /C:"string_C " && example_command.exe | findstr /C:"string_A "
However like you said it will take 4 times as long.
Related
I'm trying to search a folder for all files that include two different strings. I'm using PowerShell and the findstr command.
For example, I want to find all files that include BOTH "String: A" and "String: B", but not files that only have "String: A" OR "String: B".
I've tried using findstr /c:"String: A" /c:"String: B" *.txt in the folder, but it ended up giving me all files that had either "String: A" or "String: B", not just the files with both strings in them. findstr /? didn't explain how to essentially do an AND search, so I was wondering if anyone knew how to do such a thing.
I also tried findstr /c:"String: A" *.txt | findstr /c:"String: B" *.txt from this answer, but this ends up with no results (as in, PowerShell sits there for a very long time and never returns).
This answer was closer (I used findstr /r /c:"String: A.*String: B" *.txt), but the command returned nothing (I know from my data that there should be at least one file with both strings in it).
I'm not sure if there are formatting issues with the strings (given that they include multiple words and symbols), which is why I've been using /c: in the string formatting.
The challenge is that you seem to want to know if all of the words are present anywhere in the file, whereas findstr.exe matches patterns on a single line each.
PowerShell's more powerful findstr.exe analog, Select-String, can be combined with Group-Object to provide a solution:
$patterns = 'String: A', 'String: B'
Select-String -Path *.txt -Pattern $patterns -AllMatches |
Group-Object Path | # Group matching lines by file of origin
Where-Object {
# Does the distinct set of patterns found comprise all input patterns?
($_.Group.Pattern | Sort-Object -Unique).Count -eq $patterns.Count
} |
ForEach-Object Name
Note that this only outputs the paths of the matching files.
To also output the individual lines that contained matches for any of the patterns inside a matching file, replace ForEach-Object Name with ForEach-Object Group.
For the sake of completeness, a potential FindStr example:
%SystemRoot%\System32\findstr.exe /MIC:"String: A" *.txt | %SystemRoot%\System32\findstr.exe /F:/ /MIC:"String: B"
can anyone tell me the difference between the below two??
FILENAME=`echo /var/data`
and
FILENAME=/var/data
in unix scripting.
Both variants will give you the same result.
The big difference is that the first variant, using commands inside a pair of backticks, gives you the possibility to perform more advanced commands than simple echo, and use the output from the command (or piped chain of commands) and assign that to the variable.
For example, lets say you have a command which give some lines of text of output, one line containing e.g. Path: /var/data. To get the path you could use the commands
command_with_output | grep "Path: " | sed 's/Path: //'
The above chain of commands searches the output of command_with_output for a line containing "Path: ", then removes the "Path: " part of that line.
Using the above chained command, together with the backticks you could then do
FILENAME=`command_with_output | grep "Path: " | sed 's/Path: //'`
I'm trying to convert some cmd script to a makefile with no success.
The script is:
for /F "eol=* tokens=2,3*" %%i in (%VERSION_FILE_PATH%\VersionInfo.h,%VERSION_FILE_PATH%\Version.h) do (
if %%i==%MAJOR% set MAJOR_VALUE=%%j
if %%i==%MINOR% set MINOR_VALUE=%%j
if %%i==%HOTFIX% set HOTFIX_VALUE=%%j
if %%i==%BUILD% set BUILD_VALUE=%%j
)
What the script does is searching for specific string in each line and gets the string followed.
for example: #define MAJOR 4
I'm searching for MAJOR and getting the 4.
My question is how to do it in makefile.
If these lines always have the same structure, you could do it this way with awk:
tester:
cat test | grep MAJOR | awk '{print $$3}'
Where I made a little test file that just contains
#define MAJOR 4
You could loop over each line, grepping for the token you want, and then grabbing the third value with awk. Note that you need the double $ to escape string expansion by make.
I am running FINDSTR command to find specific text in .txt files. I want to print matching lines as well as 1 previous line.
findstr "ActualStartDate:" * > a.txt
if my file is like this
abcd
defg
cds
ActualStartDate: invalid date
Result should be like this
cds
ActualStartDate: invalid date
try this with grep for Windows:
grep -1 "ActualStartDate:" *.txt
output is eg.:
file.txt-cds
file.txt:ActualStartDate: invalid date
There is a tool written as a batch file that can do this easily, which uses built in Windows scripting.
findrepl.bat - http://www.dostips.com/forum/viewtopic.php?f=3&t=4697
Windows command line, I want to search a file for all rows starting with:
# NNN "<file>.inc"
where NNN is a number and <file> any string.
I want to use findstr, because I cannot require that the users of the script install ack.
Here is the expression I came up with:
>findstr /r /c:"^# [0-9][0-9]* \"[a-zA-Z0-9_]*.inc" all_pre.txt
The file to search is all_pre.txt.
So far so good. Now I want to pipe that to another command, say for example more.
>findstr /r /c:"^# [0-9][0-9]* \"[a-zA-Z0-9]*.inc" all_pre.txt | more
The result of this is the same output as the previous command, but with the file name as prefix for every row (all_pre.txt).
Then comes:
FINDSTR: cannot open |
FINDSTR: cannot open more
Why doesn't the pipe work?
snip of the content of all_pre.txt
# 1 "main.ss"
# 7 "main.ss"
# 11 "main.ss"
# 52 "main.ss"
# 1 "Build_flags.inc"
# 7 "Build_flags.inc"
# 11 "Build_flags.inc"
# 20 "Build_flags.inc"
# 45 "Build_flags.inc(function a called from b)"
EDIT: I need to escape the dot in the regex also. Not the issue, but worth to mention.
>findstr /r /c:"^# [0-9][0-9]* \"[a-zA-Z0-9_]*\.inc" all_pre.txt
EDIT after Frank Bollack:
>findstr /r /c:"^# [0-9][0-9]* \"[a-zA-Z0-9_]*\.inc.*" all_pre.txt | more
is not working, although (I think) it should look for the same string as before then any character any number of times. That must include the ", right?
You are missing a trailing \" in your search pattern.
findstr /r /c:"^# [0-9][0-9]* \"[a-zA-Z0-9]*.inc\"" all_pre.txt | more
The above works for me.
Edit:
findstr /r /c:"^# [0-9][0-9]* \"[a-zA-Z0-9]*\.inc.*\"" all_pre.txt | more
This updated search string will now match these lines from your example:
# 1 "Build_flags.inc"
# 7 "Build_flags.inc"
# 11 "Build_flags.inc"
# 20 "Build_flags.inc"
# 45 "Build_flags.inc(function a called from b)"
Edit:
To circumvent this "bug" in findstr, you can put your search into a batch file like this:
#findstr /r /c:"^# [0-9][0-9]* \"[a-zA-Z0-9_]*\.inc" %1
Name it something like myfindstr.bat and call it like that:
myfinsdtr all_pre.txt | more
You can now use the pipe and redirection operators as usual.
Hope that helps.
I can't really explain the why, but from my experience although findstr behaviour with fixed strings (e.g. /c:"some string") is exactly as desired, regular expressions are a different beast. I routinely use the fixed string search function like so to extract lines from CSV files:
C:\> findstr /C:"literal string" filename.csv > output.csv
No issue there.
But using regular expressions (e.g. /R "^\"some string\"" ) appears to force the findstr output to console and can't be redirected via any means. I tried >, >>, 1> , 2> and all fail when using regular expressions.
My workaround for this is to use findstr as the secondary command. In my case I did this:
C:\> type filename.csv | findstr /R "^\"some string\"" > output.csv
That worked for me without issue directly from a command line, with a very complex regular expression string. In my case I only had to escape the " for it to work. other characters such as , and . worked fine as literals in the expression without escaping.
I confirmed that the behaviour is the same on both windows 2008 and Windows 7.
EDIT: Another variant also apparently works:
C:\> findstr /R "^\"some string\"" < filename.csv > output.csv
it's the same principle as using type, but just using the command line itself to create the pipe.
If you use a regex with an even number of double quotes, it works perfectly. But your number of " characters is odd, redirection doesn't work. You can either complete your regex with the second quote (you can use range for this purpose: [\"\"]), or replace your quote character with the dot metacharacter.
It looks like a cmd.exe issue, findstr is not guilty.
Here is my find, it's related to the odd number of double quotes not redirecting from within a batch script. Michael Yutsis had it right, just didn't give an example, so I thought I would:
dataset:
"10/19/2022 20:02:06.057","99.526755039736002573"
"10/19/2022 20:02:07.061"," "
"10/19/2022 20:02:08.075","85.797437749585213851"
"10/19/2022 20:02:09.096","96.71306029796799919"
"10/19/2022 20:02:10.107","4.0273833029566628028"
I tried using the following to find just lines that had a fractional portion of a number at the end of each line.
findstr /r /c:"\.[0-9]*\"$" file1.txt > file2.txt
(a valid regex string surrounded by quotes that has one explicit double quote in it)
needed to become
findstr /r /c:"\"[0-9]*\.[0-9]*\"$"" file1.txt > file2.txt
so it could identify the entire decimal (including the explicit quotes).
I tried just adding another double quote at the end of the string ($"" ) and the command worked and generated file2.txt, but it didn't match any lines in the file, so the extra trailing double quote becomes part of the regex string, I guess, and it doesn't match anything. Including the leading double quote around the full decimal was necessary, and fine for my needs.