CMD Search a directory to Find a string inside a file - cmd

I need to find the files in a directory that have specific strings, using Windows CMD prompt.
E.g., I need to find the files that have a string like this:
<h1>Select an Item</h1>

"findstr" iswhat you are looking for.
findstr /I "<h1>Select\ an\ Item</h1>" *.*
findstr is the command, /I is a flag to match the string case insensitive. "<h1>Select\ an\ Item</h1>" is your string (note the escaped spaces!) and *.* means "in all files in this directory".
The basic syntax is findstr "seachString" filename.ext.
You may replace filename.ext with *.ext or *.* to filter cretin file types or look in all files.
This will look only in the current directory and not recursively.
More information about the command findstr documentation

The command you require is fundamentally findstr.
type
findstr /?
at the prompt for directions.
The command that may work for you is
findstr /m /g:"a file containing your string or strings" *
or
findstr /m /L /c:"<h1>Select an Item</h1>" *
Where some experimentation with the contents of the "quoted string" may be required, especially wrt characters line <>() and others with a particular meaning to cmd.exe.

Find some string inside all text files in current directory:
cls & for %i in (*.txt) do find /i "search text" < "%i" && (echo : %i & echo -)
Tested in Win 10

Related

Windows cmd: piping the dir list output into find (or findstr) is not working

I need to do some very big Windows searches for some specific searchterms in th contents of all the files in a folder and all sub-folders. The GUI search facility is not finding all my tests, so I would like to try to use find via the cmd.
I can list all filenames in raw data format using:-
dir /S /B
I can successfully search for the searchterm in thecontents of all files in a single folder using :-
find "Searchterm" *.*
But there are thousands of recursive sub-folders, so when I pipe the output from the dir listing to the find (and exclude the filename parameter):
dir /S /B | find "Searchterm"
I am getting no results.
Furthermore, I have also successfully sent all the dir /B /S filenames to a text file:-
dir /S /B >> filenames.txt
and using type to pipe the contents of each file from the list to the find :-
type filenames.txt | find "Searchstring"
This does not work either. What am I missing? Microsoft's documentation suggests exactly the same format in https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/find as I am trying.
The solution to your question(s) should be clear by reading the output from %SystemRoot%\System32\findstr.exe /? ENTERed in a Command Prompt window.
I'd advise that you use the /L, literal, option for your initial code.
Direct results example:
%SystemRoot%\System32\findstr.exe /I /L /P /S "Searchstring" *
If you first send the filenames to a text file, e.g. Dir /B /S /A:-D 2>NUL 1>"filenames.txt", you could use the following idea:
%SystemRoot%\System32\findstr.exe /F:"filenames.txt" /I /L /P "Searchstring"
Just be aware, in this case, that unless you include a path outside of the target tree when initially creating filenames.txt, it will include itself in its own content. That means your FindStr command will also pick up any matches in that file too.

Recursively search for folder whose name may contain space(s), in a specific directory

As said in Q-title, I am trying to find a particular directory called Local State, but it could be spelled by some Apps as LocalState or Local State, anyone of which is surely present in every Apps' folder inside %USERPROFILE%, which I am trying to list out.
Now for that I had to write two lines, one for finding LocalState which works well, and it's as given:
pushd "%USERPROFILE%"
for /d /r %%h in (LocalState) do if exist "%%h" echo "%%h"
popd
But with the almost same line when I try to find Local State folder it doesn't show the paths as expected, as it adds extra quotes around the searched folder. See this:
pushd "%USERPROFILE%"
for /d /r %%h in ("Local State") do if exist "%%h" echo "%%h"
popd
gives this, which is weird, as any action can't be taken on this extra quoted path:
....
....
"C:\Users\<Username>\AppData\Local\BraveSoftware\Brave-Browser\User Data\"Local State""
"C:\Users\<Username>\AppData\Local\Google\Chrome\User Data\"Local State""
....
....
Now I am wondering is it possible with one line only I am able to search folder name like LocalState or Local State in the specified folder with batch script ? Something like this?
for /d /r %%h in ("Local? State") do if exist "%%h" echo "%%h"
And it would show paths in regular proper quoted format like:?
....
....
"C:\Users\<Username>\AppData\Local\BraveSoftware\Brave-Browser\User Data\Local State"
"C:\Users\<Username>\AppData\Local\Google\Chrome\User Data\Local State"
....
....
Or if that's not at all possible, then how can I find folder names with spaces and echo those paths in proper quoted format with no extra, unrequired quotes ?
Why do the FOR command lines not work as expected?
The strings LocalState and "Local State" are not interpreted by for as folder name to search for because of neither containing * nor ?. The command FOR searches only for non-hidden files or with option /D for non-hidden folders on specifying a wildcard pattern.
There was tried:
for /d /r %%h in (LocalState) do if exist "%%h" echo "%%h"
for /d /r %%h in ("Local State") do if exist "%%h" echo "%%h"
The command lines above result in searching recursively for directories (including hidden ones) and assign to the loop variable h each found directory with full path not enclosed in " concatenated with the specified string LocalState or "Local State".
Example: The current directory is C:\Temp with following directory structure:
C:\Temp
Development & Test(!)
Folder 2
The IF condition is executed with following strings assigned to loop variable h:
C:\Temp\LocalState
C:\Temp\Development & Test(!)\LocalState
C:\Temp\Folder 2\LocalState
C:\Temp\"Local State"
C:\Temp\Development & Test(!)\"Local State"
C:\Temp\Folder 2\"Local State"
The directory names 4 to 6 are problematic on as they contain themselves two double quotes resulting in executing the IF conditions with not correct specified names for file system entries – directory or file or reparse point – that makes no difference for IF in this case with no backslash at end.
Somebody might think this behavior of FOR does not make sense, but that behavior is useful in some use cases, for example on creation of a file with a specific name in each folder of a directory tree.
The problem here is that there cannot be added * at beginning or at end, i.e. use *LocalState or "Local State*" because of that can result in false positives. FOR would really search now for non-hidden directories of which name ends with LocalState or starts with Local State.
So the usage of the following command line would not be good:
for /d /r %%h in (*LocalState "Local State*") do echo "%%h"
What are possible solutions?
A very fast possible solution is:
for /F "delims=" %%h in ('dir "%USERPROFILE%\LocalState" "%USERPROFILE%\Local State" /AD /B /S 2^>nul') do echo "%%h"
There is started in background one more cmd.exe with option /c and the specified command line within ' appended as additional arguments.
DIR searches first
for just directories because of option /AD
with the name LocalState or the name Local State
in the specified directory %USERPROFILE% and
all its subdirectories because of option /S and
outputs just the fully qualified directory name because of the options /B (bare format) and /S.
DIR is so smart to search in each directory for both directories names. So the entire directory tree is searched by DIR only once for both directory names at the same time.
The started cmd.exe closes itself once DIR finished.
The cmd.exe instance processing the batch file captures all fully qualified folder names output by DIR and FOR processes them now line by line.
The FOR option delims= defines an empty list of delimiters to turn off the default line splitting behavior on normal spaces and horizontal tabs. That is required because of each folder name should be assigned completely one after the other to the loop variable h for further processing and not just the part up to first space character in a full folder name.
Other solutions are:
for /F "delims=" %%h in ('dir "%USERPROFILE%\Local*State" /AD /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /L /C:LocalState /C:"Local State"') do echo "%%h"
for /F "delims=" %%h in ('dir "%USERPROFILE%\Local*State" /AD /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /R /C:"Local *State"') do echo "%%h"
DIR searches in both cases for directories of which name starts with Local and ends with State (case-insensitive) recursively in specified folder %USERPROFILE%.
There is used FINDSTR on the first command line to filter out all false positive found directories of which fully qualified directory name does not end with the case-insensitive and literally interpreted string LocalState or Local State like Local & State.
There is used FINDSTR on the second command line to filter out all false positive found directories of which fully qualified directory name is at end not matched by the case-insensitive interpreted regular expression Local *State which matches LocalState and Local State and also Local State (two spaces) because of * is interpreted here as preceding character (the space) zero or more times. Please notice the difference. In a wildcard pattern * means any character zero or more times, but not here in the regular expression search string interpreted by FINDSTR where it means preceding character zero or more times.
The two solutions searching with DIR for the directories with a wildcard pattern and using FINDSTR to filter out false positive found directories are a bit slower than the solution using just DIR with the two directory names to search for.
In all provided solutions could be modified the DIR option /AD to /AD-L to ignore junctions and symbolic directory links (reparse points) and find just real directories.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
echo /?
findstr /?
for /?
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on the FOR command lines to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line with using a separate command process started in background.
This will work in a batch-file run under cmd on windows.
FOR /F "delims=" %%A IN ('powershell -NoLogo -NoProfile -Command ^
"(Get-ChildItem -Recurse -Directory -Filter 'Local*State').FullName"') DO (ECHO Directory name is %%~A)
Requires PowerShell 5.1 or later. Find your version with the command
$PSVersionTable.PSVersion.ToString() or (Get-Host).Version.ToString()

Extract line of text from .txt file using CMD?

was wandering if there is a way to extract a line of text which contains certain value from a .txt file using CMD. For example using "type filepath\example.txt" will open the whole file and in my case I am working trough a software which doesn't allow CTRL+F option and .txt files are massive.
Is there any way I could specify certain word in order to get that whole line of text or to open only .txt files which have that word within them. For example I have 1000 .txt files and all of them contain the same text but only one of them has a word "EXAMPLE" in it. Could I use some command to find and open that file using CMD.
Thank you.
I have 1000 .txt files and all of them contain the same text but only one of them has a word "EXAMPLE" in it. Could I use some command to find and open that file using CMD.
a) find the file(s) that have the desired string:
findstr /m "EXAMPLE" *.txt
b) find the file (assuming, only one contains the string; else it will open all matching files) and open the file in notepad:
for /f "delims=" %a in ('findstr /m "EXAMPLE" *.txt') do "%a"
c) find the one line that has the string:
findstr "EXAMPLE" *.txt
The findstr.exe solution from Stephen would be less typing. But, using Select-String allows the use of a much more complete implementation of regex. All supported Windows systems have PowerShell available. This works in a batch-file run by cmd on windows and at the command prompt. Given that this would likely be put into a batch-file, the amount of typing is not very significant.
#powershell.exe -NoLogo -NoProfile -Command ^
Get-ChildItem -Path '.\*.txt' ^| ^
ForEach-Object { Select-String -Pattern 'example' -Path $_ } ^| ^
Select-Object -Property Filename,Line
Not the most elegant alternative, I agree, and I am certain someone will tell me how it could be bettered. The key is it uses basic find a string (you can set as I have to be case insensitive) in a file then reports filename and line number, Line [9] in this case.
#forfiles /m *.txt /C "cmd /c (find /n /i \"For example\" "#file"1>nul) &&if %errorlevel%==0 (find /n /i \"For example\" "#file"2>nul)"
When used in a batch file it could look something like this, but see caveats below
Finder$.cmd
#echo off & Title Find wally String in a file
set "string=where's Wally"
if not "%1"=="" set "string=%~*"
forfiles /m *.txt /C "cmd /c (find /n /i \"%string%\" "#file"1>nul) &&if %errorlevel%==0 (find /n /i \"%string%\" "#file")"
echo/ & pause & exit /b
It is not perfect but note its not case sensitive (using /i), it can readily fail if *.txt files are not plain text and as written will only accept a short unquoted string of up to 9 words ( avoid " or other punctuation). It works in local directory with *.txt, but you could alter those as require to first say cd /d f:\mylogs and search *.log files.
Finally you asked to open the file thus we can simplify for that task to call an editor like notepad or with some fetteling one that accepts line numbers (but that is another question)
forfiles /m *.txt /C "cmd /c (find /n /i \"%string%\" "#file"1>nul) &&if %errorlevel%==0 (notepad.exe "#file")"
Everything below is related to unix bash terminal, so please install Linux Subsystems if you are using Windows. Or even Linux itself :)
You can open specific file in a text editor like Vim or Nano in terminal. They offer the "CTRL+F" function.
Below you can see me searching for the "gameId" keyword in the file game_stats.js, which I opened via $ vim game_stats.js.
P.S. To quite vim you need to type :q :)
Use grep command as advised in this answer https://stackoverflow.com/a/16957078/13212398
Example for the command that recursively searches for any .js or .txt files that contains "let" in the current directory (.).
$ grep --include=\*.{js,txt} -rnw -e "let" .
./this_test.js:18:let bob = new Person('Bob');
./this_test.js:19:let bill = new Person('Bill', bob);
./TUD-2Q-WDB/checkers-in-delft/public/javascripts/game_state.js:99: let pieces = []

Use Windows findstr to list files not containing a string

From Windows CMD I can use
findstr -m subroutine *.f90
to list all files with suffix .f90 containing "subroutine". To list all .f90 files not containing the string I can do something like
dir /b *.f90 > files.txt
findstr -m subroutine *.f90 > files_with_string.txt
and then write a script to list the lines in files.txt not found in files_with_string.txt. Is there a more elegant way?
There is a /v option in findstr, but that wouldn't help here.
Process each file with a for loop, try to find the string and if it doesn't find it (||), echo the filename:
for %a in (*.f90) do #findstr "subroutine" "%a" >nul || echo %a
(above is command line syntax. For use in a batchfile, use %%a instead of %a (all three occurences))
I needed to search for filenames which contained one specific string ("up"), but did not contain another string ("packages").
However, I was hoping to run it from the command line.
This is actually possible to do, you just have to call findstr twice.
Mine looked like:
dir /B /S up | findstr /I "up" | findstr /I /v "packages"
That means:
search all directories (/S & subdirs)
give me the bare formatting (/B)
and pass it through (| pipe) findstr (/I ignore case) to find ones that have "up" then
pass the results (| pipe) through findstr again but this time ignore all that
contain (/v) "packages"
If you have items like:
c:\test\packages\up
c:\extra\thing\up
c:\extra\thing\packages\up
c:\extra\test\up
c:\extra\test\nothing
The results would be only the ones that contain "up" but do not contain "packages"
c:\extra\thing\up
c:\extra\test\up
Call findstr /v multiple times on result
In other words you can keep passing the result into another findstr with /v to remove the ones that have additional words you don't want.

Is there a way to exclude certain values/variables from a wildcard in a for loop

for /d %%A IN (u:\mainfolder\*) DO if not exist "%%A\%var1%" mkdir "%%A\subfolder"
I want to exclude certain folders in the directory u:\mainfolder\ so that mkdir executes on all but a few of the folders there. Is there a way to exclude certain folders given the use of the wildcard?
If you only have 2 or 3 to exclude you can do something like this.
for /d %%A IN (u:\mainfolder\*) DO if /i not "%%A"=="u:\mainfolder\Name1ToExclude" if /i not "%%A"=="u:\mainfolder\Name2ToExclude" if not exist "%%A\%var1%" mkdir "%%A\subfolder"
Otherwise if you have more, you probably want to use a table of names to exclude.
The command FOR does not support an exclude option.
But the task can be achieved using the commands DIR and FINDSTR executed by FOR.
#echo off
set "MainFolder=U:\mainfolder"
for /F "delims=" %%A in ('dir "%MainFolder%\*" /AD /B ^| %SystemRoot%\System32\findstr.exe /E /I /L /V /X /C:"Exclude Folder 1" /C:ExcludeFolder2 /C:FolderToExclude3 2^>nul') do if not exist "%MainFolder%\%%A\%var1%" mkdir "%MainFolder%\%%A\subfolder"
set "MainFolder="
The command DIR is executed to output only directories in directory specified with environment variable MainFolder because of the options /AD (attribute directory) and /B (bare format). The directory names are output by DIR without path, just the directory names.
The output of DIR is piped as input to FINDSTR using redirection operator |.
FINDSTR searches in all lines for one of the strings specified with option /C as literal string because of option /L not enclosed in double quotes or enclosed in double quotes because of directory name contains a space character or one of these characters: &()[]{}^=;!'+,`~
The search is case-insensitive because of option /I.
A match is only positive if the enter line matches completely with a search string because of /X which means the entire directory name must match completely with one of the search strings.
The option /V results in an inverted output by FINDSTR. Instead of printing the lines matching with one of the search strings, it prints the lines (= directory names) not matching with any of the search strings.
The filtered directory names without path are processed line by line by FOR.
The redirection operators | and > must be escaped with caret character ^ in the finally executed command line:
dir "U:\mainfolder\*" /AD /B | C:\Windows\System32\findstr.exe /E /I /L /V /X /C:"Exclude Folder 1" /C:ExcludeFolder2 /C:FolderToExclude3 2>nul
This command line is executed by FOR with using a separate command process started in the background. The redirection operators | and > must be escaped with ^ to be interpreted as literal characters on parsing the entire FOR command line by Windows command interpreter before executing command FOR with the rest of the line.
On a longer list of directories to exclude I suggest to write the directory names into a plain text file and use option /G: of FINDSTR instead of specifying them all with /C: on command line.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
echo /?
findstr /?
for /?
set /?
Read also the Microsoft article about Using Command Redirection Operators.

Resources