Been working on a systematic file search script to retrieve the name of all documents in a directory, and all sub directories that contain a determined search string. Essentially, it will log the search results. It would be nice to have it also search the file names, but that's not yet important.
Code:
#echo off
echo - Will search all files in current directory, and subdirectories.
echo - Will ignore case sensitivity.
echo - Will only search for term within readable documents.
set /p searchfilter=Search Filter:
set results=%CD%\results.txt
echo Searching...
echo Results: > "%results%"
for /f "usebackq tokens=*" %%i in (`dir /s/b/A:-D/o:e`) do (
find /i "%searchfilter%" "%%~nxi" >nul && echo %%~nxi >> "%results%"
)
echo Search complete.
pause
Run-down: System requests a string from the user. Then, the system saves a handle to the results file (thought that would fix the problem, didn't). The system then filters all files, excluding folders, from the directory, and sub directories, printing the bare name of the file (with extension), where it will proceed to scan each file for the search string, and save any positive search results to the text file.
It seems on a number of files, I receive a "File not found - " error, and need help identifying it. My guess, is that it has something to do with trying to find a sub directory file without the directory handle.
find /i "%searchfilter%" "%%i" >nul && echo %%~nxi >> "%results%"
should fix your problem, as you've flagged yourself. If you are searching for a file named fred.txt that exists in a subdirectory but mot in the root of the subtree scanned, then you'll get a File not found error.
Your choice whether you echo just the name and extension to results or whether you echo the full filename, of course. Personally, I'd use `%%i and get the whole thing.
I'd also change
for /f "usebackq tokens=*" %%i in (`dir /s/b/A:-D/o:e`) do (
to
for /f "delims=" %%i in ('dir /s/b/A:-D/o:e') do (
but that's just a matter of style in this case.
This should give you a tool to search filenames in the current folder tree and log the results to a file - in c:\path\file.ext format.
Replace searchstring with your search term and remove *.doc if you want to search all files, or replace it with *.doc *.txt *.ini *.src if you want to filter a number of filetypes.
#echo off
dir /b /s /a-d *.doc |findstr /r /i ".*\\.*searchstring.*" >results.txt
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.
So I am trying to create a batch file that will take a pdf file in the same directory as the batch file and output the file name (sans extension). I used this code to accomplish this:
#echo off
for /r "C:\Users\me\Test Folder" %%G in (*.pdf) do set "name=%%~nG"
This works fine. The next step is to search another directory and find a directory within the searched directory whose name matches the output of the above code (stored in the %name% variable). Here's what I tried:
dir "P:\Accounting\Acc Pay" | find %name% | set "loc=%%~dp"
The goal of the above code was to find only the directories that had the same name as the original pdf file and then set the drive and path of the output to a variable %loc%. I think this is where I messed up.
Once the path to the folder is set to %loc%, I then am supposed to finish with this line:
move .\*.pdf %loc%
This would take all the pdf files (there will only be one in the directory at once) in the directory with the batch file and move it to the path currently stored in the %loc% variable.
In total the code looks like this:
#echo off
for /r "C:\Users\me\Test Folder" %%G in (*.pdf) do set "name=%%~nG"
for /r %%A in ('dir "P:\Accounting\Acc Pay" | find %name%') do set "loc=%%~dpA"
move .\*.pdf %loc%
However, the code seems to move the pdf file into the same location it was already in (ie the folder with the batch file). I assume the %loc% variable is not working properly. Any help much appreciated.
Like #Magoo said (^|). And you surely want to add the following switches for the dir command: /b for "bare format" (name only) and /ad for "Attribute Directory" to return folder names only. find needs its's argument quoted, and for safety, the destination for the move command should also be quoted. Your find could benefit from /i to make it case-insensitive.
I personally would do it with nested loops to avoid creating superflouos variables:
#echo off
for /r "C:\Users\me\Test Folder" %%G in (*.pdf) do (
for /r %%A in ('dir /b /ad "P:\Accounting\Acc Pay" ^| find /i "%%~nG"') do (
move "%%G" "%%~dpA"
)
)
Bonus: should there be more than one .pdf file (maybe after the Weekend or Holidays), this would process all of them correctly in one go.
Depending on your naming structures, consider replacing find /i "%%~nG" with findstr /iblc:"%%~nG" (see findstr /?to find out what the switches mean)
(Note to prevent confusion: findstr is the only command (as far as I'm aware) that supports concatenating switches into one. /iblc is the same as /i /b /l /c)
I'm trying to list out file names excluding their extension,
How I want it:
File1
File2
File3
How it currently is:
File1.txt
File2.txt
File3.txt
I tried using
#echo off
dir /A:-D /B
pause
but it isn't working. I tried it in both a batch file and in command prompt.
Am I using the right command?
Use FOR and ECHO to achieve this
For example, assuming the extension is always .txt:
for %f in ("*.txt") do #echo %~nf
Instead of using DIR, we are using the FOR command to go through the list and sending each one to ECHO, with the "~n" option inserted into the %f, to cause the extension to be not shown.
An alternative is
FORFILES /c "cmd /c echo #fname"
However with this I get quotation marks around each output filename, which isn't what you want.
If running inside a batch file, you need to double the %'s for variables
for %%f in ("*.txt") do #echo %%~nf
If you need to handle multiple file extensions
As long the directory doesn't contain any subdirectories whose names have an extension, you can generalise the *.txt to *.*:
for %f in ("*.*") do #echo %~nf
If you may have some filenames with only an extension
Where the file has an extension but nothing before it, e.g. .gitignore, the resulting empty ECHO command will output an inane message, such as ECHO is on. To avoid this ruining your onward plans, you can filter out lines containing ECHO is, with the FIND command and the /V option:
for %f in ("*.*") do #echo %~nf | find /v "ECHO is"
If your local language causes DOS to output something other than ECHO is then this filtering will not work. And it will miss any file that happens to contain ECHO is in the filename.
To search subdirectories too, add '/R' to the 'for'
for /R %f in ("*.png") do #echo %~nf | find /v "ECHO is"
Conclusion
This is all crazy, of course, but this is the agonising price we pay for using Batch language instead of an actual sensible language. I am like an alcoholic, promising to all and sundry that I will never write a line of Batch code again, and then finding myself coming back to do so again, sheepishly.
It'll be much easier in PowerShell
(Get-ChildItem -File).BaseName
or
Get-ChildItem | ForEach-Object { $_.BaseName }
Get-ChildItem can be replaced with the aliases ls, gci or dir and ForEach-Object can be replaced with %
So from cmd you can run either of these to achieve the purpose
powershell -Com "(ls -File).BaseName"
powershell -C (ls^ -File).BaseName
powershell (ls^ -af).BaseName
To add to Eureka's answer, the vanilla dir command cannot achieve what you're looking for.
C:\Users\jacob>dir /?
Displays a list of files and subdirectories in a directory.
DIR [drive:][path][filename] [/A[[:]attributes]] [/B] [/C] [/D] [/L] [/N]
[/O[[:]sortorder]] [/P] [/Q] [/R] [/S] [/T[[:]timefield]] [/W] [/X] [/4]
[drive:][path][filename]
Specifies drive, directory, and/or files to list.
/A Displays files with specified attributes.
attributes D Directories R Read-only files
H Hidden files A Files ready for archiving
S System files I Not content indexed files
L Reparse Points - Prefix meaning not
/B Uses bare format (no heading information or summary).
/C Display the thousand separator in file sizes. This is the
default. Use /-C to disable display of separator.
/D Same as wide but files are list sorted by column.
/L Uses lowercase.
/N New long list format where filenames are on the far right.
/O List by files in sorted order.
sortorder N By name (alphabetic) S By size (smallest first)
E By extension (alphabetic) D By date/time (oldest first)
G Group directories first - Prefix to reverse order
/P Pauses after each screenful of information.
/Q Display the owner of the file.
/R Display alternate data streams of the file.
/S Displays files in specified directory and all subdirectories.
/T Controls which time field displayed or used for sorting
timefield C Creation
A Last Access
W Last Written
/W Uses wide list format.
/X This displays the short names generated for non-8dot3 file
names. The format is that of /N with the short name inserted
before the long name. If no short name is present, blanks are
displayed in its place.
/4 Displays four-digit years
Switches may be preset in the DIRCMD environment variable. Override
preset switches by prefixing any switch with - (hyphen)--for example, /-W.
Additionally, as an alternative to the suggestion to use ("*.txt"), if your file list includes multiple extensions you might either exclude different extensions or use *.* to get all files with a . in the name. Play around with that glob to get what you want out of it.
This is possible with a dir command and a for loop:
#echo off
for /F "delims= eol=" %%A IN ('dir /A-D /B') do echo %%~nA
If you want the full path without the extension, try:
#echo off
for /F "delims= eol=" %%A IN ('dir /A-D /B') do echo %%~dpnA
For cmd one-line:
for /F "delims= eol=" %A IN ('dir /A-D /B') do echo %~nA
And for the full path without the extension, try:
for /F "delims= eol=" %A IN ('dir /A-D /B') do echo %~dpnA
These small programs, loop through all the files in the folder except directories, and echo only the filenames/full paths without the extension.
dir -Name -File
This is for PowerShell
I am trying to write a command that runs from location of the program. The program asks user to type in a folder to search for, when the folder is found, I need a list of directories to its subfolders. Below is my code so far:
ECHO OFF
ECHO Enter name for your target search folder
SET /P searchf=[Please type desired search forder]
for /d %%a in ("%searchf%".) do dir /ad /on /s /b "%%a" >> %searchf%.txt
GOTO End
:End
Assuming the target folder is called "test", I want to have a result like this:
C:\Users\IT\test\pany\all
C:\Users\IT\test\ondy\part\clear
C:\Users\IT\pany\test\check\apps
C:\Users\IT\pand\all\check\test
So far my code returns dir till where the "test" was found.
As JosefZ pointed out, wild cards will help:
ECHO OFF
ECHO Enter name for your target search folder
SET /P searchf=[Please type desired search forder]
dir /ad /on /s /b "*%searchf%*"
Since there is only one search term, you do not need a for loop.
Using a variable file name I considered difficult, that's why I first changed it to be a fixed filename, until I figured out that for having a list of directories on the screen you can use the dir output directly.
I have been reading great posts in this forum and got close to what I want to do but couldn't figure out the exact code.
I want to create a windows batch file to do following:
Perform a looped search for each line item of a text file (this is a list of keyword) to locate files in a a specific directory
For this search partial match is okay.
Each time a file is found, move it to a predefined directory (e.g. C:\temp\search_results)
Thanks.
I'm not running Windows at the moment, so I can only post some ideas, not the solution.
1) Use for /f to iterate over file contents.
2) Use find "%Keyword%" %SourceDir% to get the list of matching files. You will have to parse out file names from the output of find.
2a) As an alternative, you can iterate over files in the source dir (with nested for) and call find for each file, discarding its output and using its exit code (%ERRORLEVEL%) to decide whether the file matches (it will return 0 if there is a match and nonzero if there is no match). Something like this:
for %%F in (%SourceDir%\*) do (
find "%Keyword%" %%F > nul
if not errorlevel 1 (echo File %%F matches) else (echo File %%F does not match)
)
3) Move matching files with move.
There are multiple problems.
FIND /i "%A%" ... can't work, the name of the FOR-Varibale is %%A
And the second proble: With FIND you check the content of the file not the name.
And you should use indention to avoid too much parenthesis.
You better try
FOR /F "tokens=*" %%A IN (%listfile%) DO (
FOR %%f in (%searchdir%\*) do (
set "filename=%%~f"
set replaced=!filename:%%A=!
if !replaced! NEQ !filename! (
echo !filename! contains '%%A'
)
)
)
It tries to replace %%A inside of the filename with .
If the replaced is not equal the filename, the filename must contain %%A
I wrote the following code but not sure if I am in the right track. Here is my setup:
list.txt file contents are (my keywords for the filename search) --
one
two
five
ten
six
f1 folder contains --
four.txt
one.txt
three.txt
I want to move the matching ones to F2 folder, but the code simplicity I am using echo instead.
My code is:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SET listfile=D:\batchtest\list.txt
SET searchdir=D:\batchtest\f1
FOR /F "tokens=*" %%A IN (%listfile%) DO (
FOR %%f in (%searchdir%\*) do (FIND /i "%A%" %%f
if errorlevel 1 (
echo Search failed) else (
echo Search successful
)
)
)
)
It is running but not finding matching filenames.
Thanks.