Looking for the command line (or batch) that will do the following,
I have 3 levels of directories and need to search for a specific string contained in text files, searching all files, 1 level subdirectory down.
So I know this will recursively search for the string
findstr /S "STRING" *
But I don't want the search to go father than only 1 subdirectory level down.
Seems like a simple thing but I could not find anything solid. The closest thing I could find was something like this thread..
windows batch to recursively scan files in 1 level subfolders
However, before going batch is there a simpler (command line) way to this rather, apparently simple task?
Thanks for your time!
This should do it from the command line and write file.log into the current folder
for /d %a in (*) do findstr "STRING" "%a\*">>file.log
Child Directory Search Only (No Parents or Grandchildren)
Here is a one line command to enumerate the current working directory children directories dir /ad/b and search each directory for files containing the search string. Results are saved out to a text file.
for /f "delims=" %A in ('dir /ad/b') do #findstr "STRING" "%~A\*" >> results.txt
Note: That as currently configured, a result line will be output for each matching line in a file. Meaning that multiple find results may be output for a single file.
Example of results.txt
ChildFolderA\File1.txt:line with STRING
ChildFolderA\File1.txt:another line with STRING in file1
ChildFolderA\File2.txt:another file and line with STRING
ChildFolderB\File5.txt:another folder with a file containing the search STRING
#echo off
setlocal enableextensions
(#for /d %%a in (*) do #for %%b in ("%%~fa\*") do #echo(%%~fb)|findstr /f:/ /c:"string" > file.txt
This will enumerate all the files one level down and send this list of files to a findstr command. findstr will search the string into the indicated list and send output to final file
To use from command line, replace the double percent signs %% with single ones %
Related
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
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.
Please can someone tell how to find particular pattern in list of files.
I use the command:
dir *.txt /b /s >> C:\Users\Amrendra\Downloads\NIT_Testing\fileList.txt
In fileList.txt I have a list of files.
Now I want to find a certain pattern say abc in all the files listed.
So I want each line containing that pattern to be written into a new file.
Please suggest as I am completely new to batch command.
Thanks
I'm not sure if I got you completely right. You've echoed the names of all .txt files from some folder into one text file. Now you want to check it line by line for filenames containing some substring in the file name. Is that correct? If it is, here is the solution:
#ECHO OFF
SET targetFile=C:\Some\Path\SomeTextFile.txt
SET sourceFile=C:\Some\Path\Source.txt
SETLOCAL EnableDelayedExpansion
TYPE NUL>%targetFile%
FOR /F "tokens=*" %%L IN (sourceFile) DO (
SET templine=%%L
SET templine=!templine:abc=!
IF NOT !templine!==%%L (
ECHO %%L>>%targetFile%
)
)
Let's take a look on how it works: first we put the path to the file containing the file names into the variable %sourceFile% and the path to the target file into the variable %targetFile%. We need EnableDelayedExpansion to be able to work with changing variables inside the FOR-loop. TYPE NUL>%targetFile% simply clears the target file in case there are some entries from former runs.
The main work is done inside the FOR-loop. We read the source file line by line and want to check if the line contains the substring we are looking for. To do this we first store the line (%%L) in a temporary variable. Then we replace any occurrences of the search string with an empty string, means we simply remove abc from the temporary string. Finally we compare our modified temporary string with the original one. If they are equal we can be sure that the serch string abc was not in the original string. The other way around, if the strings differ, the substring was in the original string. So in the second case we do ECHO %%L>>%targetFile% which means we write the whole file name containing the search substring into our target file. Et voilà, we're done!
EDIT: As you want to search all listed files for the substring, here the new code:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SET sourceFile=C:\Users\Amrendra\Downloads\NIT_Testing\fileList.txt
SET targetFile=C:\Users\Amrendra\Downloads\NIT_Testing\newList.txt
SET searchString=abc
TYPE NUL>%targetFile%
FOR /F "tokens=*" %%L IN (%sourceFile%) DO (
FINDSTR %searchString% "%%L">NUL
IF !ERRORLEVEL!==0 ECHO %%L>>%targetFile%
)
Here we are using findstr to check if a text file contains the string we are searching. As findstr usually would output the line which contains the searched string (which we don't want) we simply mute the command using >NUL. What we actually need is the ERRORLEVEL! If the string was found in a file findstr will set ERRORLEVEL to 0 or to 1 otherwise. So the only thing we have to do is to check if !ERRORLEVEL!==0.
The following code displays file names in a directory and sub-directories and puts the results into results.txt. I am having trouble sorting the list. Where do I put the sort option?
for /r %i in (*) do #echo %~ni >> results.txt
Use the dir command:
dir /ON /B >> results.txt
The /ON sorts by name.
The /B returns in "Bare" (name only) format.
If you add /S it will recurse all sub-directories, but will include the file path.
You'll need to do the sort later, once the results are written to the text file. Add a second line to your batch file reading:
sort results.txt
The results will be written back to results.txt. Alternatively you can get it to go faster by using
sort /O:NewResults.txt results.txt
And getting it to write to a different file.
This can be done with a single line:
(for /r %i in (*) do #echo %~ni)|sort /o results.txt
writing the output to a file with sort switch /o is faster than redirecting sort > file.txt
Only one file gets written, so it should be even faster.
(Note: this is command line syntax. For use in a batchfile, replace each %i with %%i)
I have almost 2000 files which I need to rename.
The files are named in the following format: PART1#PART2#PART3.pdf
I would like to batch rename the files so that PART2 is moved before PART1 e.g. PART2#PART1#PART3.pdf
PART 1 = A random document reference e.g. 124244
PART 2 = A reference number e.g. 12-12434-A
PART 3 = A short description e.g. Part 1
The # symbol separates each of these parts.
Is there a simple utility which I can use to make this change?
Use a batch file
#echo off
setlocal enableextensions disabledelayedexpansion
cd /d "c:\where\thefiles\are"
for /f "tokens=1,2,* delims=#" %%a in ('
dir /b /a-d *.pdf ^| findstr /r /b /e /i /c:"[^#][^#-]*#[^#][^#]*#..*\.pdf"
') do echo ren "%%a#%%b#%%c" "%%b#%%a#%%c"
What this code does is
Get the file list: a dir command asking for .pdf files in a bare format without the folders
Filters to only get the adecuated files: findstr command, searching for a regular expression that matches the beginning and end of the lines, ignoring case. The expression that is tested against the file names is : a non # character, followed by a sequence of non # or - characters (to avoid renaming the files twice), followed by a #, followed by a non # and a sequence of non # characters, followed by a # and any sequence of characters ending in .pdf
The for command splits the names using the # as token delimiter and for each one do the rename.
Rename operations are only echoed to console. If the output is correct, remove the echo command