Batch file to perform a looped search based on the line items of a text file - windows

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.

Related

Loop through files in a folder and check if they have different extensions

I have a folder that contains files; each document should have .pdf and .xml format. I need to write a BAT file to run from a scheduled task to verify that both documents exist for each.
My logic is:
loop through files in the folder
strip each file to its name without extension
check that same name files exist for both .xml and pdf.
if not mark a flag variable as problem
when done, if the flag variable is marked, send an Email notification
I know how to use blat to sending email, but I'm having trouble to execute the loop. I found a way to get path and file name without extension but can't merge them.
I've used batch files a few time, before but I'm far from an expert. What am I missing?
Here's the code I have so far:
set "FolderPath=E:\TestBat\Test\"
echo %FolderPath%
for %%f in (%FolderPath%*) do (
set /p val=<%%f
For %%A in ("%%f") do (
Set Folder=%%~dpA
Set Name=%%~nxA
)
echo Folder is: %Folder%
echo Name is: %Name%
if NOT EXIST %FolderPath%%name%.xml
set flag=MISSING
if NOT EXIST %FolderPath%%name%.pdf
set flag=MISSING
)
echo %Flag%
pause
There is no need for fancy code for a task such as this:
#Echo Off
Set "FolderPath=E:\TestBat\Test"
If /I Not "%CD%"=="%FolderPath%" PushD "%FolderPath%" 2>Nul||Exit/B
Set "flag="
For %%A In (*.pdf *.xml) Do (
If /I "%%~xA"==".pdf" (If Not Exist "%%~nA.xml" Set "flag=MISSING")
If /I "%%~xA"==".xml" (If Not Exist "%%~nA.pdf" Set "flag=MISSING")
)
If Defined flag Echo=%flag%
Timeout -1
Something like this :
set "FolderPath=E:\TestBat\Test\"
pushd "%FolderPath%"
for %%a in (*.xml) do (
if exist "%%~na.pdf"(
echo ok
) else (
rem do what you want here
echo Missing
)
)
popd
Is this what you want?
#echo off
setlocal enabledelayedexpansion
set "FolderPath=E:\TestBat\Test\"
echo !FolderPath!
for /f "usebackq delims=" %%f in (`dir !FolderPath! /B`) do (
set /p val=<%%f
For %%A in ("%%f") do (
Set Folder=%%~dpA
Set name=%%~nxA
)
echo Folder is: !Folder!
echo Name is: !name!
if NOT EXIST !FolderPath!!name!.xml set flag=MISSING
if NOT EXIST !FolderPath!!name!.pdf set flag=MISSING
)
echo Flag: !flag!
pause
endlocal
You should reformat your code and keep in mind that the grama for batch file is critical. BTW, if you are trying to update the existing batch variable and read it later, you should enable localdelayedexpansion and use ! instead of %.
Keep it simple:
#echo off
pushd "E:\TestBat\Test" || exit /B 1
for %%F in ("*.pdf") do if not exist "%%~nF.xml" echo %%~nxF
for %%F in ("*.xml") do if not exist "%%~nF.pdf" echo %%~nxF
popd
This returns all files that appear orphaned, that is, where the file with the same name but the other extension (.pdf, .xml) is missing. To implement a variable FLAG to indicate there are missing files, simply append & set "FLAG=missing" to each for line and ensure FLAG is empty initially. Then you can check it later by simply using if defined FLAG.
Note: This does not cover the e-mail notification issue. Since I do not know the BLAT tool you mentioned, I have no clue how you want to transfer the listed files to it (command line arguments, temporary file, or STDIN stream?).
In case there is a huge number of files in the target directory, another approach might be better in terms of performance, provided that the number of file system accesses is reduced drastically (note that the above script accesses the file system within the for loop body by if exist, hence for every iterated file individually). So here is an attempt relying on a temporary file and the findstr command:
#echo off
pushd "E:\TestBat\Test" || exit /B 1
rem // Return all orphaned `.pdf` files:
call :SUB "*.pdf" "*.xml"
rem // Return all orphaned `.xml` files:
call :SUB "*.xml" "*.pdf"
popd
exit /B
:SUB val_pattern_orphaned val_pattern_missing
set "LIST=%TEMP%\%~n0_%RANDOM%.tmp"
> "%LIST%" (
rem // Retrieve list of files with one extension:
for %%F in ("%~2") do (
rem /* Replace the extension by the other one,
rem then write the list to a temporary file;
rem this constitutes a list of expected files: */
echo(%%~nF%~x1
)
)
rem /* Search actual list of files with the other extension
rem for occurrences of the list of expected files and
rem return each item that does not match: */
dir /B /A:-D "%~1" | findstr /L /I /X /V /G:"%LIST%"
rem // Clean up the temporary file:
del "%LIST%"
exit /B
To understand how it works, let us concentrate on the first sub-routine call call :SUB "*.pdf" "*.xml" using an example; let us assume the target directory contains the following files:
AlOnE.xml
ExtrA.pdf
sAmplE.pdf
sAmplE.xml
So in the for loop a list of .xml files is gathered:
AlOnE.xml
sAmplE.xml
This is written to a temporary file but with the extensions .xml replaced by .pdf:
AlOnE.pdf
sAmplE.pdf
The next step is to generate a list of actually existing .pdf files:
ExtrA.pdf
sAmplE.pdf
This is piped into a findstr command line, that searches this list for search strings that are gathered from the temporary file, returning non-matching lines only. In other words, findstr returns only those lines of the input list that do not occur in the temporary file:
ExtrA.pdf
To finally get also orphaned .xml files, the second sub-routine call is needed.
Since this script uses a temporary file containing a file list which is processed once by findstr to find any orphaned files per extension, the overall number of file system access operations is lower. The weakest part however is the for loop (containing string concatenation operations).

Batch file to sort files and list missing

I am trying to write a batch file that would read rows/lines from a txt file containing a list. The batch file would then copy the documents that match, and produce a list of missing files.
So far, the code successfully copies the files that it matches, but it also fills the "Missing.txt" file will exact contents of the input list, rather than simply the missing files.
#echo off
::Requests name of list file to be used by batch file
echo Enter list file name and press enter
set /p var=
mkdir %userprofile%\Desktop\%var%\
set /A lis=1
::Logic to search for files based on contents of list inputted by user at start.
for /f "tokens=*" %%i in (%var%.txt) DO (
call :processline %%i
IF NOT EXIST %%i (echo %%i>>%userprofile%\Desktop\%var%\Missing.txt)
)
pause
::Function called processline
::Assigns a string/value to variable "line"
::Copies a file with name = "line" to the user's desktop
::Renames the file to include a number reference, based on original list being searched
::Increments number for next file to be searched,copies and renamed
:processline
echo line=%*
xcopy /s %*.* %userprofile%\Desktop\%var%
move /Y %userprofile%\Desktop\%var%\%*.pdf %userprofile%\Desktop\%var%\%lis%_%*.pdf
set /A lis=%lis%+1
:eof
I suspect my problem is within the "for" logic, although there might be a way to input missing file names within the processline function.
Any help or advice would be much appreciated.
It's command order: :processline subroutine moves something, maybe including %%i file. I'd use next code snippet:
IF EXIST "%%~i" (
call :processline %%i
) ELSE (
>>"%userprofile%\Desktop\%var%\Missing.txt" echo %%i
)

Write script to search the solution

I'm working on removing a large number of old and unused images from our website. We run ASP.NET with C# code behind, and do our work out of Visual Studio (2013). Right now I'm just going through our images directory and searching the solution for the image file name. While we have some filenames that follow a pattern and can be done in a group using regex, this is still rather tedious. Is there a way that I can write a batch script (or anything) to search the solution for every file in this directory? I can imagine pseudocode like
for file in images_directory
if file not in solution
delete file
but is this possible?
Technically we're just moving the files into another folder to be safe, so I guess the actual pseudocode would be more like
for file in images_directory
if file not in solution
move file to backup_directory
Within your solution file, find all references to .csproj files. Within each .csproj file, find all include lines. Within each included file, find all lines containing references to images. Copy each relevant line to a temporary list. This will make searching faster than searching every .cs file multiple times for every image.
For each graphic file, use findstr to perform a regexp search for /\bfilename\b/i within the temporary list. If not found, use conditional execution to initiate a move of the orphaned image to backup.
Save this with a .bat extension, modify the first three set lines to appropriate values, and give it a shot. By default, it only pretends to move. If you're satisfied that the simulations will produce correct results, remove echo from the move line near the bottom to let the script off its leash.
#echo off
setlocal
set "image_dir=c:\path\to\images"
set "sln_file=c:\path\to\solution\Project1.sln"
set "backup_dir=c:\path\to\backup"
set "remember=%temp%\proj_images.txt"
for %%I in ("%sln_file%") do pushd "%%~dpI"
rem // .sln -> .csproj -> .cs -> images. Find image references and remember.
del "%remember%" >NUL 2>NUL
for /f "delims=" %%I in ('findstr /i ".csproj\>" "%sln_file%"') do (
rem // %%I contains lines matching /.csproj\b/ig
for %%p in (%%I) do if exist "%%~p" (
rem // %%p contains a .csproj filename
for /f "delims=" %%J in ('findstr /i "\<include\>" "%%~p"') do (
rem // %%J contains lines matching /\binclude\b/ig
for %%c in (%%J) do if exist "%%~c" (
rem // %%c contains the filename of an include
findstr /i ".png\> .jpg\> .gif\> .bmp\> .tif\>" "%%~c" >>"%remember%" && (
echo Images referenced within %%~nxc. I'll remember this.
)
)
)
)
)
rem // for each image file in image_dir (recursive)
for /r "%image_dir%" %%I in (*.png *.jpg *.gif *.bmp *.tif) do (
rem // regexp test for /\bfilename.ext\b/i
findstr /i "\<%%~nxI\>" "%remember%" >NUL || (
rem // non-zero exit status of findstr means not found
echo %%~nxI is not referenced by any files included in the solution's projects.
rem // *********************************************************
rem // REMOVE "ECHO" FROM THE FOLLOWING LINE TO ENABLE THE MOVES
rem // *********************************************************
echo move "%%~fI" "%backup_dir%"
)
)
del "%remember%" >NUL 2>NUL
echo Press any key to exit.
pause >NUL
Is this what you had in mind?
All together If I understand correctly You first want to obtain all images files from directory. Using PowerShell:
$imageFiles = Get-ChildItem 'path/to/image/directory' -Recurse | Where-Object { !($_.PSIsContainer) }
This grabs all files excluding Directories. Then:
$solutionText = Get-Content 'path/to/solution/file.csproj' | Out-String
ForEach ($file in $imageFiles ) {
if ($solutionText -match $file.Name) {
# Move to another folder
}
}
The only issue is that you'd need to make sure that the filenames don't have a chance of matching elsewhere on the file giving false positives.

Batch file giving File Not Found error

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

Finding a string within 2 files and then moving the files. Batch

I recently asked a question about finding files with the same ID and then moving them.
Although the files I am moving do not have the same ID. Instead they have the same string within the files.
Here is the code I have for finding the same ID of files
ECHO OFF
setlocal enableDelayedExpansion
set "source=C:SORCEFOLER"
set "destBIAK=C:BIAKFOLER"
set "destBIPO=C:BIPOFOLDER"
set "POfile=BIPO"
SET "AKfile=BIAK"
pushd "%source%"
for %%F in ("%POfile%*") do (
set "setID=%%F"
set "setID=!setID:%POfile%=!"
if exist "%AKfile%!setID!" robocopy /mov "%source%" "%destbiak%" "%%F"
if exist "%AKfile%!setID!" robocopy /mov "%source%" "%destbipo%" "%AKfile%!setID!"
)
popd
Like I said, I need to actually find a string that matches in the two different and then move them based on the the string.
Here is a example of the beginning of the first file
H|0003341369|20131123
I can not post the entire PO file because it contains customer names and addresses that are proprietary information of the person I am making the file for.
here is the entire AK file
0003341369|SO-02052|20131124|A|
That just a bunch of numbers. Notice that digits 3 through 12 of the PO file match digits 1 though 10 of the AK file.
There are multiple AK files and PO files in one folder.
I was thinking that the script would find the ID of the AK file, search all the PO files until it finds the one that matches and then moves them.
I have looked at several scripts that search for a string, they then output the file name with the string to a certain file. I cant figure out how to output this as a variable.
Thanks
This should take the first term in every AK.* file (the characters before the first | character such as 0003341369 ) and search for it in every PO.* file.
If it finds the term inside two || characters (such as |0003341369| ) then it will move those files to a folder - and after comparing all PO.* files it will move the AK.xxx file to the same folder.
#echo off
for %%a in (AK.*) do (
MD "folder %%~na"
for /f "delims=|" %%b in ('type "%%a" ') do (
for %%c in (PO.*) do findstr "|%%b|" "%%c" >nul && move "%%c" "folder %%~na" >nul
)
move "%%a" "folder %%~na"
)

Resources