Batch Script to find string in directory and all subdirectories - string

I want to write a batch file which used the find command to find a string in the parent directory and all sub directories, and prints that output to a text file, then opens the text file when done. My code so far looks like this:
#echo off
set /p "var1= Enter the String to Find: "
for /F "delims=" %a in ('dir /B /S *.txt') do #(find /i "%var1" "%a" 1>nul 2>&1 && find /i "%var1" "%a") >> result.txt
start result.txt
But this is currently not even writing anything to result.txt, even though I am sure that where I am searching the string appears in multiple .txt files. I know it must be something syntax-wise but I can't seem to figure it out.

You have a few mistakes in your script:
There should not be a space after the equals sign of a set command. Specifically, remove the space after set /p "var1=.
To expand variables, you have to put a percent sign before and after the variable name, so instead of %var use %var%.
Not directly related to your problem, but why are you invoking find twice?
I've also made use of a temporary file, so that result.txt won't be searched by find.
Note that for if you're running the batch script from a file, You need to use double percent signs when you use loop variables, for example: %%a
Anyway, here's the fixed script, hopefully doing what you intended to do:
#echo off
set RESULT_FILE="result.txt"
set /p "var1=Enter the String to Find: "
pushd %~p0
type NUL > %RESULT_FILE%.tmp
for /f "delims=" %%a in ('dir /B /S *.txt') do (
for /f "tokens=3 delims=:" %%c in ('find /i /c "%var1%" "%%a"') do (
for /f "tokens=*" %%f in ('find /i "%var1%" "%%a"') do if %%c neq 0 echo %%f
)
) >> "%RESULT_FILE%".tmp
move %RESULT_FILE%.tmp %RESULT_FILE% >nul 2>&1
:: Open the file
"%RESULT_FILE%"
popd

just findstr abc *
in contrast, findstr /v will print all without abc

Related

How to make the scenario happen in batch script

#echo off
start COMMAND_ONE
for /f "tokens=1-6 delims=," %%i in ('type file1.txt') do (
start COMMAND_TWO with arguments as %%i to %%n
)
for /f "tokens=1-6 delims=," %%i in ('type file2.txt') do (
COMMAND_TWO with arguments as %%i to %%n
)
for /f "tokens=1-6 delims=," %%i in ('type file3.txt') do (
start command_two with arguments as %%i to %%n
)
for /f "tokens=1-6 delims=," %%i in ('type file4.txt') do (
start COMMAND_TWO with arguments as %%i to %%n
)
pause
The point here is
I want COMMAND_ONE to be executed first and after that is complete i want the loops to execute in concurrent manner and only one cmd window should be open providing status like ITERATION_1 OF LOOP_1 is complete and ITERATION_2 OF LOOP_3 is complete and so on....
Or just a single line ALL LOOPS COMPLETED at the end of all loops completed in the single cmd window.
You could perhaps just run something like this:
#echo off
start "" /b /wait COMMAND_ONE
set "files=file1.txt file2.txt file3.txt file4.txt"
for %%a in (%files%) do (
for /f "tokens=1,* delims=," %%i in (%%a) do (
start "" /b /wait COMMAND_TWO with arguments as %%i to %%n
)
)
/b simply starts a command without a new window while /wait will wait for the command/program to finish before lanching the next one.
So Commands explained in order:
Set all files in a variable, loop through the files performing the required commands, while waiting on each to complete before going to the next one.
We also do not need to use tokens=1-6 as tokens=1,* is a better option. From cmd.exe see:
for /?
start /?
set /?

Windows Batch : Wrong behavior when double clicked - Works fine on prompt

THE QUESTION IS EXACTLY THAT I DID THAT AND NOT WORKED
This script is running fine if I go to the prompt and call the file.bat, get all files *.gsc and clean the lines without that string.
But when I double clicked didn't work as expected, and even the first file is deleted everytime I run, and none of the remaining files were cleaned. :\
#echo off
set "string_to_find=level.waypoints\["
for /f "tokens=*" %%a in ('dir /B *.gsc') do (
set "tempfile=%temp%\%%a"
if exist "%tempfile%" del "%tempfile%" >NUL
findstr /C:"%string_to_find%" "%~dp0\%%a" >> "%tempfile%"
if not errorlevel 1 (
del "%%a" >NUL
move /Y "%tempfile%" "%~dp0\%%a" >NUL
if exist "%tempfile%" del "%tempfile%" >NUL
echo File "%~dp0\%%a" processed successfully
) else (
echo Problem processing file "%~dp0\%%a"
)
)
I already tryed to use
setlocal enableDelayedExpansion
And also replace the vars for "!" instead of "%", but I'm doing something wrong... could you help me pointing what I exact I need to change to make this work also with double click?
thank you!
Well, after many hours of tryes I finally get it working with double click now. Here the final code:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "string_to_find=level.waypoints\["
for /f "tokens=*" %%a in ('dir /B *.gsc') do (
set "tempfile=!temp!\%%a"
if exist "!tempfile!" del "!tempfile!" >NUL
findstr /C:"!string_to_find!" "%~dp0\%%a" >> "!tempfile!"
if not errorlevel 1 (
del "%%a" >NUL
move /Y "!tempfile!" "%~dp0\%%a" >NUL
if exist "!tempfile!" del "!tempfile!" >NUL
echo File "%~dp0\%%a" processed successfully
) else (
echo Problem processing file "%~dp0\%%a"
)
)
cheers

Improving Windows Batch Script

The following script search thru a folder and its sub-folders and then compares each file it gets to files in the 2nd folder. If found it echo's a message to say that the file was found.
My question is how do I enhance this script to search the 2nd folder and its sub-folders for the file found in 1st dir? I only care about the file-name with extension (I do not care in which folder/sub-folder it was found, just that a duplicate file is present and causing compiler errors)
I thought one of the ways would be to output all file names to a file and then take the file as input in 2nd part and loop thru the 2nd folder, but I am sure there must be a cleaner way.
O/S: Windows 2003
:bof
rem #echo off
cls
setlocal
:init
set dirA=X:\tst\pfsrc\
set dirB=X:\tst\cbsrc\
if not exist "%dirA%" echo dirA not found & goto :EOF
if not exist "%dirB%" echo dirB not found & goto :EOF
for /f "delims=" %%I in ('dir /b /a:-d /s "%dirA%" 2^>NUL') do if exist "%dirB%%%~nxI" echo %%~nxI does exist in "%dirB%"
:eof
this excerpt will try to find %%a in all dirs of %dirB% recursively
for /d /r %%d in (%dirB%\*) do (
if exist "%%d\%%~nxa" echo %%d\%%~nxa
)
Thank you for putting me on the correct track :-) Code now works
:bof
#echo off
cls
setlocal
:init
set dirA=X:\tst\pfsrc\
set dirB=X:\tst\cbsrc\
if not exist "%dirA%" echo dirA not found & goto :EOF
if not exist "%dirB%" echo dirB not found & goto :EOF
for /f "delims=" %%I in ('dir /b /a:-d /s "%dirA%" 2^>NUL') do for /r "%dirB%" %%d in (%%~nxI) do if exist "%%d" echo %%d
:eof

Getting substring of a token in for loop?

I have this for loop to get a list of directory names:
for /d %%g in (%windir%\Assembly\gac_msil\*policy*A.D*) do (
echo %%g
)
Output:
C:\WINDOWS\Assembly\gac_msil\policy.5.0.A.D
C:\WINDOWS\Assembly\gac_msil\policy.5.0.A.D.O
C:\WINDOWS\Assembly\gac_msil\policy.5.20.A.D.O
C:\WINDOWS\Assembly\gac_msil\policy.5.25.A.D.O
C:\WINDOWS\Assembly\gac_msil\policy.5.35.A.D.O
C:\WINDOWS\Assembly\gac_msil\policy.5.55.A.D.O
C:\WINDOWS\Assembly\gac_msil\policy.5.60.A.D.O
C:\WINDOWS\Assembly\gac_msil\policy.5.70.A.D.O
C:\WINDOWS\Assembly\gac_msil\policy.6.0.A.D.O
I want to get the folder names starting with "policy" but echo %%g:~29 doesn't work.
I also tried to set x=%%g and then echo %x:~29% and still doesn't work.
So, how do I get substring from token in for loop?
Of course that set x=%%g and a substring extraction of x should work, but be aware that if the substring is taken inside a FOR loop, it must be done with ! instead of % (Delayed Expansion):
setlocal EnableDelayedExpansion
for /d %%g in (%windir%\Assembly\gac_msil\*policy*A.D*) do (
set x=%%g
echo !x:~29!
)
On the other hand, if you want to know "How to get the last part (name and extension) of a token in for loop", the answer is: use the ~Name and ~eXtension modifiers in %%g replaceable parameter:
for /d %%g in (%windir%\Assembly\gac_msil\*policy*A.D*) do (
echo %%~NXg
)
I recently had a similar question, and I wanted to compile here the 3 working solutions:
Use EnableDelayedExpansion in your batch file, as in the accepted answer
#echo off
setlocal EnableDelayedExpansion
for /d %%g in (%windir%\Assembly\gac_msil\*) do (
set x=%%g
echo !x:~29!
)
Use for /f to process the output of a dir command
for /f "tokens=*" %%g in ('dir /ad /b %windir%\Assembly\gac_msil\*') do #echo %%g
And finally, the optimal solution in this case, using enhanced variable substitution. See the end of the help at for /? for more information on this syntax.
for /d %%g in (%windir%\Assembly\gac_msil\*) do #echo %%~nxg
A simple
dir /B %windir%\Assembly\gac_msil\*policy*A.D*
should do the trick. If you want to loop over it:
for /f %%g in ('dir /B %windir%\Assembly\gac_msil\*policy*A.D*') do (
echo %%g
)

How to remove prefixes in strings on Windows command line?

Suppose I wanted to echo every executable inside the %programfiles% folder
cd %programfiles%
for /r . %i in (*.exe) do echo "%~i"
but it yields
c:\program files\program1\program1.exe
c:\program files\program2\program2.exe
and I want
program1\program1.exe
program2\program2.exe
How to remove those prefixes?
You could use the string replace function of batch
pushd %programfiles%
set "prefix=%programfiles%"
setlocal DisableDelayedExpansion
for /r . %i in (*.exe) do (
set "progPath=%~i"
setlocal EnableDelayedExpansion
set "progPath=!progPath:%prefix%=!"
echo !progPath!
endlocal
)
popd
Put this in a batch file and run, it should do the job.
#echo off
setlocal ENABLEDELAYEDEXPANSION
cd %programfiles%
for /r . %%i in (*.exe) do (
set pth=%%~fi
set val=!pth:%cd%\=!
echo !val!
)
This answer is based on jebs
This one is if your batch file is not on the same drive as that you're working on so a different approach needs to be taken.
The code has comments included.
#echo off
::
rem Based of the answer: https://stackoverflow.com/a/6335341/8262102
title Removes prefix from directories example...
set "dirBase=C:\Program Files\Common Files"
cd /d %dirBase% &rem changes to the directory.
setlocal DisableDelayedExpansion
for /r . %%A in (*.exe) do (
set "progPath=%%~A"
setlocal EnableDelayedExpansion
set "progPath=!progPath:%dirBase%=!"
echo .!progPath!
endlocal
)
echo/ & pause & cls

Resources