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.
Related
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.
This question already has an answer here:
At which point does `for` or `for /R` enumerate the directory (tree)?
(1 answer)
Closed 3 years ago.
I can add a prefix to a series of text files using:
:: rename files
for %%a in (*.txt) do (
ren "%%a" "Seekret file %%a"
:: ECHO %%a Seekret file %%a
)
which will turn
a.txt
b.txt
c.txt
into
Seekret file a.txt
Seekret file b.txt
Seekret file c.txt
However, the above code seems to rename the first file twice with the prefix. I end up with
Seekret file Seekret file a.txt
and I have no idea why. Any ideas?
Use
for /f "delims=" %%a in ('dir /b /a-d *.txt') do (
What is happening is that the version you are using sees the renamed-file as a new file. The dir version builds a list of the filenames and then executes the for on each line, so the list is already built and static and cmd isn't trying to operate on a moving target.
Also - use rem, not :: within a code-block (parenthesised sequence of instructions) as this form of comment is in fact a broken label and labels are not allowed in a code block.
Yes, this can happen, especially on FAT32 and exFAT drives because of these file systems do not return the list of directory entries matched by a wildcard pattern to calling executable in an alphabetic order. for processes the directory entries matching *.txt one after the other and the command ren results in changing the directory entries, i.e. the file names list is modified while iterating over it.
The solution is using:
for /F "eol=| delims=" %%I in ('dir *.txt /A-D /B 2^>nul') do ren "%%I" "Seekret file %%I"
FOR runs in this case in background %ComSpec% /c with the command line specified between ' which means with Windows installed into directory C:\Windows:
C:\Windows\System32\cmd.exe /C dir *.txt /A-D /B 2>nul
So one more command process is started in background which executes DIR which
searches in current directory
just for files because of option /A-D (attribute not directory)
including files with hidden attribute set (use /A-D-H to exclude hidden files)
matching the wildcard pattern *.txt
and outputs in bare format just the file names because of option /B.
An error message output by DIR to handle STDERR in case of not finding any directory entry matching these criteria is suppressed by redirecting it to device NUL.
Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
The file names without path are output by DIR to handle STDOUT of background command process. This output is captured by FOR respectively the command process executing the batch file.
After started command process terminated itself, FOR processes the captured list of file names. All changes done on directory during the loop iterations do not matter anymore for that reason. The file names list does not change anymore.
The options eol=| delims= are needed to get the complete file names assigned one after the other to loop variable I even on starting with ; or containing a space character. eol=| redefines default end of line character ; to a vertical bar which no file name can contain. delims= defines an empty list of delimiters to disable default line splitting behavior on normal spaces and horizontal tabs.
Note: :: is an invalid label and not a comment. Labels inside a command block are not allowed and usually result in undefined behavior on execution of the command block. Use command REM (remark) for a comment.
Even better would be:
for /F "eol=| delims=" %%I in ('dir *.txt /A-D /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /B /I /L /V /C:"Seekret file "') do ren "%%I" "Seekret file %%I"
FINDSTR is used here to output from list of file names output by DIR and redirected to STDIN of FINDSTR all file names which
do not because of /V (inverted result)
begin because of option /B
case-insensitive because of option /I
with the literally interpreted because of option /L (redundant to /C:)
string Seekret file .
Option /C: is needed to specify the search string containing two spaces as using just "Seekret file" would result in searching literally and case-insensitive for either Seekret OR file at begin of a line. In a search string specified with just "..." each space is interpreted by FINDSTR as an OR expression like | in a Perl regular expression string.
A search string specified with /C: is interpreted implicitly as literal string, but with using /R (instead of /L) it would be possible to get this string interpreted as regular expression string on which a space is interpreted as space and not as OR expression. It is possible to specify multiple search strings using multiple times /C:.
My recommendation on using FINDSTR: Use always either /L or /R to make it clear for FINDSTR and for every reader of the command line how FINDSTR should interpret the search string(s) specified with "..." or with /C:"...".
I guess I'll throw my hat in too, since I'm not really a fan of looping through dir output and no one else is currently accounting for this script already having been run:
#echo off
set "dir=C:\Your\Root\Directory"
set "pfx=Seekret file "
setlocal enabledelayedexpansion
for /r "%dir%" %%A in (*.txt) do (
set "txt=%%~nA"
if not "!txt:~0,13!"=="%pfx%" ren "%%A" "%pfx%%%~nxA"
)
pause
for /r will loop recursively through all .txt files, set each one as parameter %%A (per iteration), set a variable txt as parameter %%A reduced to just its name (%%~nA), and then it compares the first 13 characters of the text file to your example prefix (which is 13 characters long when you include the space: Seekret file) - if they match the loop does nothing; if they do not match, the loop will rename %%A to include the prefix at the beginning. If you don't want it to be recursive, you can use for %%A in ("%dir%"\*.txt) do ( instead. Other than that, you'll just change !txt:~0,13! depending on what your prefix is or how many letters into a filename you want to check. You also don't have to set your directory and prefix variables, I just prefer to do so because it makes the block look cleaner - and it's easier to go back and change one value as opposed to every place that value occurs in a script.
Reference: for /r, ren, variable substrings
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.
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
I would like to get all the paths that ends with a given suffix (like 'example/subpath/string') . Is there any simple way of doing it in Windows cmd?
dir /ad /s /b c:\startingPoint | findstr /l /e /c:"example\subpath\string"
dir folders (/ad) from c:\startingPoint and below (/s) in bare format (/b). Filter the list with findstr, we only want the lines with the literal (/l) "example\subpath\string" (/c) at the end of the line (/e)
Adapt as needed