Regarding FIND Instruction using Batch File. Storing result in a variable - windows

I am searching a string on a list of files under many subfolders. If the string is found, then i'll perform more statements (which is not important anyways on my question).
So what I did is use the FIND instruction, using /c option. Then store the result of the FIND trimming the right most last character (which is the number of occurence of the string on a file). See below for the sample code...
for /F "delims=" %%A in ('find /c "PROGRAM-ID." "C:\FORTEST\CBL001.cbl"') do SET findstr=%%A
SET findstr=%findstr:~-1%
echo %findstr%
That code above gives me
1
Which is correct because the word "PROGRAM-ID" only occurred once in CBL001.cbl..
Now if I implement this code on a for loop to check for all files within a folder...
for /r "C:\FORTEST\" %%G in (*.*) do (
for /F "delims=" %%A in ('find /c "PROGRAM-ID." %%G') do SET findstr1=%%A
SET findstr1=%findstr1:~-1%
echo %findstr1%
)
The echo is returning
ECHO is off.
I dont understand how inserting the for loop into another for loop would mess up the code....
Thanks for reading.
=======
EDIT: Problem solved. Thanks to #npocmaka
So originally, before all this fiasco regarding storing FIND result into variable, I was using ERRORLEVEL to determine if the FIND instruction found the string or not (which sounds much simpler), but the ERRORLEVEL is not returning the correct value even if the string was not found. Hence my current solution of storing the result of FIND and using that data for comparison.
But it seems DelayedExpansion was the original culprit causing ERRORLEVEL to not produce the correct value.
See below for final code.
for /r "C:\FORTEST" %%G in (*.*) do (
find "PROGRAM-ID." %%G
if !ERRORLEVEL! EQU 0 (
echo ITS A COBOL
::do something
) else (
echo NOPE NOT A COBOL
)
)
Also thanks to other replies, tho I didnt bother using them, but I appreciate the efforts!

find doesn't write the dashes and filenames, if it gets it's input from a pipe. And there is no need for an additional variable (findstr1):
for %%G in (*.*) do (
for /F "delims=" %%A in ('type %%G^|find /c "PROGRAM-ID."') do echo %%A %%G
)

The correct answer is using EnableDelayedExpansion
Thanks to #npocmaka

Related

How can I search for files recursively but only operate on instances where the file is found using a batch file?

The objective of my script is to search for a single filename (of which there are files of that name existing in different folders) recursively given a starting path and output the path of each file found excluding name and extension.
I've been stuck on this all morning for some reason. I have produced the below code.
#echo off
for /r D:\Workspaces\fwarrener-lglesias\Example\Example\Clients %%x in (EnterpriseSettings.config) do (
echo %%~nxx
echo %%~dpx
)
I was under the impression from other people's answers and documentation that this will only execute the commands in the 'do' clause if a file within the parentheses is found. However, when executing and piping into a file I have a ridiculous amount of unnecessary lines as it is outputting the directory it is in even when it hasn't found the file. I am confused by this as I thought the whole point of specifying a set was the at the commands in do would only execute in an instance where it finds the filename.
D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\Example\
D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\Example\Example\
D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\Example\Example\Config\
D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\Example\Example\Config\Stage\
Could anyone elighten me as to how I've mis-interpreted the usage of the for-loop or syntax?
It seems more obvious to me to do this with a DIR command. See the meaning of /A:-D-S-L in the output of the DIR /? command.
FOR /F "tokens=*" %%x IN ('DIR /S /B /A:-D-S-L "D:\Workspaces\fwarrener-lglesias\Example\Example\Clients\EnterpriseSettings.config"') DO (
echo "%%~nxx"
echo "%%~dpx"
)
The issue with your code is more than likely because For /R, (and For /D), expect a wildcard pattern.
This can be fixed by:
using the * wildcard, ("EnterpriseSettings.conf*g")
using the ? wldcard ("EnterpriseSettings.c?nfig")It must be noted however that there is a potential that non required files could be matched too, even with careful placement of the wildcard.
use a different method, such as the Dir or Where commands with their recursive options.This should match only exact filenames, example below.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
Set "dirBase=D:\Workspaces\fwarrener-lglesias\Example\Example\Clients"
Set "fileName=EnterpriseSettings.config"
If /I Not "%__CD__%"=="%dirBase%\" (
PushD "%dirBase%" 2>Nul && (Set "_=$") || Exit /B
)
For /F "Delims=" %%A In ('Dir /B/S/A-D-S-L "%fileName%" 2^>Nul') Do Echo %%~dpA
Pause
If "%_%"=="$" PopD
EndLocal
As already shown by this answer, using the dir command is a good solution, which I would prefer.
An alternative way is to use for /R as you already do, but to add if exist, like this:
for /R "D:\Workspaces\fwarrener-lglesias\Example\Example\Clients" %%x in ("EnterpriseSettings.config") do (
if exist "%%~x" if not exist "%%~x\" (
echo %%~nxx
echo %%~dpx
)
)
The if not exist part with the item plus trailing \ excludes directories with matching names.
Another way is to add a wildcard (? in this example) to force for to access the file system and to check for matching files, but to filter the result against false positives:
for /R "D:\Workspaces\fwarrener-lglesias\Example\Example\Clients" %%x in ("EnterpriseSettings?.config") do (
if /I "%%~nxx"=="EnterpriseSettings.config" (
echo %%~nxx
echo %%~dpx
)
)
I have revamped my batch script.
Tell me if this helps you in any way:
#ECHO OFF
SET path=C:\Users\<USER>\<DIRS>
SET filename=EnterpriseSettings*.config
For /R %path% %%f in (%filename%) do (
echo %%~pf
)
PAUSE
I also used ~p idiom which is Extract the path only found at: Filename parsing in batch file and more idioms

Why does my for-loop not increase my variable?

I program a batch file, but I'm new to for-loops which I need.
I now know how the syntax works, but I cannot figure out why my loop does not do what it should.
This code is an extract from my file:
#echo off & setlocal enabledelayedexpansion
set /p file=:
set /a numberofgoals=0
for /f "delims=" %%a in ("%file%.txt") do set /a "numberofgoals+=1"
echo %numberofgoals%
pause > nul
If I did everything right my output should be the length of the specified textfile and it worked for me before, but apperently I changed something in the code that I'm not sure about and the output of %numberofgoals% is everytime exactly 1 now, regardless of how long my text file is.
My question is: What have I done wrong and why is the output 1 now? I cannot even remember having changed something there...
EDIT: I changed "delims=" into "usebackq delims=" as suggested and it works now, thank you.
The quotes in the for loop's parentheses mean "process this string" rather than "read this file". Use the usebackq option to indicate that the quotes are providing a filename:
for /f "usebackq delims=" %%a in ("%file%.txt") do set /a "numberofgoals+=1"
and you should be golden.
Type help for in your cmd window for the gory details.

Finding String in Batch

I am relatively new to Batch and am having problems trying to find a string value within a txt file. I am using a neat program called CCExtactor to extract closed captioning from a file and need to grab the time of the closed captioning.
The output from CCExtractor looks like this:
###SUBTITLE#08:37#08:40#She ran away
My batch script looks like this:
for /F "delims=" %%a in (subtitle.txt) do ( echo %1|findstr /R /C:"^[^0-9][0-9]*$" )
I can't seem to get this to work! I am trying to skim the time values!
How would I go about doing this??
Here's an example.
#echo off
setlocal
set filename=subtitle.txt
for /f "delims=# tokens=2,3" %%I in ('findstr /r /c:"^###SUBTITLE#[0-9][0-9]:[0-9][0-9]#[0-9][0-9]:[0-9][0-9]#" %filename%') do (
echo start=%%I, end=%%J
)
In your for statement, you should make the delims value to be #. That way you can echo out %%d and %%e to get the start time and end time.

Get string from file in batch

Task in CMD.
1) How can I compare if string is in string? I checked manual here for "Boolean Test "does string exist ?"" But I can't understand the example or it does not work for me. This piece of code, it is just a try. I try to make a string compare of filter some sting if there is a tag <a> in a line.
FOR /f "tokens=* delims= usebackq" %%c in ("%source%") DO (
echo %%c
IF %%c == "<a" (pause)
)
So while I read a file, it should be paused if there is a link on a line.
2) I have one more ask. I would need to filter the line if there is a specific file in the link, and get content of the link. My original idea was to try to use findstr with regex, but it seems not to use sub-patterns. And next problem would be how to get the result to variable.
set "pdf=0_1_en.pdf"
type "%source%" | grep "%pdf%" | findstr /r /c:"%pdf%.*>(.*).*</a>"
So in summary, I want to go through file and if there is a link like this: REPAIRED: *
<b>GEN 0.1 Preface</b>
I forgot to style this as a code, so the inside of code was not displayed. Sorry.
Warnning: we don't know the path, only the basic filename.
Get the title GEN 0.1 Preface. But you should know, that there are also similar links with same link, which contain image, not a text inside a tag.
Code according Aacini to be changed a little bit:
#echo off
setlocal EnableDelayedExpansion
set "source=GEN 0 GENERAL.html"
set "pdf=0_1_en.pdf"
echo In file:%source%
echo Look for anchor:%pdf%
rem Process each line in %source% file:
for /F "usebackq delims=" %%c in ("%source%") do (
set "line=%%c"
rem Test if the line contain a "tag" that start with "<a" string:
set "tag=!line:*<a=!"
if not "!tag!" == "!line!" (
rem Take the string in tag that end in ">"
for /F "delims=^>" %%a in ("!tag!") do set "link=%%a"
echo Link found: !link!
if "!link!" == "GEN 0.1 Preface" echo Seeked link found
)
)
pause
Still not finished
Although your question is extensive it does not provide to much details, so I assumed several points because I don't know too much about .PDF files, tags, etc.
#echo off
setlocal EnableDelayedExpansion
set "source=GEN 0 GENERAL.html"
set "pdf=0_1_en.pdf"
echo In file: "%source%"
echo Look for anchor: "%pdf%"
rem Process each line in %source% file:
for /F "usebackq delims=" %%c in ("%source%") do (
set "line=%%c"
rem Test if the line contain "<a>" tag:
set "tag=!line:*<a>=!"
if not "!tag!" == "!line!" (
rem Test if "<a>" tag contain the anchor pdf file:
if not "!tag:%pdf%=!" == "!tag!" (
rem Get the value of "<b>" sub-tag
set "tag=!tag:<b>=$!"
set "tag=!tag:</b>=$!"
for /F "tokens=2 delims=$" %%b in ("!tag!") do set title=%%b
echo Title found: "!title!"
)
)
)
pause
Any missing point can be added or fixed, if you give me precise details about them.
EDIT: I fixed the program above after last indications from the OP. I used $ character to get the Title value; if this character may exist in original Tag, it must be changed by another unused one.
I tested this program with this "GEN 0 GENERAL.html" example file:
Line one
<a>href="/Dokumenter/EK_GEN_0_X_en.pdf" class="uline"><b>GEN 0.X Preface</b></a>
Line three
<a>href="/Dokumenter/EK_GEN_0_1_en.pdf" class="uline"><b>GEN 0.1 Preface</b></a>
Line five
and get this result:
In file: "GEN 0 GENERAL.html"
Look for anchor: "0_1_en.pdf"
Title found: "GEN 0.1 Preface"
EDIT: New faster method added
There is a simpler and faster method to solve this problem that, however, may fail if a line contains more than one tag:
#echo off
setlocal EnableDelayedExpansion
set "source=GEN 0 GENERAL.html"
set "pdf=0_1_en.pdf"
echo In file: "%source%"
echo Look for anchor: "%pdf%"
for /F "delims=" %%c in ('findstr /C:"<a>" "%source%" ^| findstr /C:"%pdf%"') do (
set "tag=%%c"
rem Get the value of "<b>" sub-tag
set "tag=!tag:<b>=$!"
set "tag=!tag:</b>=$!"
for /F "tokens=2 delims=$" %%b in ("!tag!") do set title=%%b
echo Title found: "!title!"
)
pause
First, one important question: does this really have to be implemented via a CMD script? Would you be able to go with VBScript, PowerShell, C#, or some other scripting/programming language? CMD is a notoriously painful scripting environment.
Secondly, I'm not sure if this answers your question--it's a bit unclear--but here's a quick trick you can use to see in CMD to see if a given string contains another substring:
setlocal enableextensions enabledelayedexpansion
set PATTERN=somepattern
for /f "delims=" %%f in (somefile.txt) do (
set CURRENT_LINE=%%f
if "!CURRENT_LINE:%PATTERN%=!" neq "!TEMP!" (
echo Found pattern in line: %%f
)
)
The idea is that you try to perform string replacement and see if anything was changed. This is certainly a hack, and it would be preferable if you could instead use a tool like findstr or grep, but if you're limited in your options, something like the above should work.
NOTE: I haven't actually run the above script excerpt, so let me know if you have any difficulty with it.
I have modified the way to do it. I realized that it is better to find name of pdf document first. This is my almost completed solution, but I ask you if you could help me with the last point. The last replacing statement does not work because I need to remove closing tag b. Just to get the title.
#echo off
setlocal EnableDelayedExpansion
set "source=GEN 0 GENERAL.html"
set "pdf=0_1_en.pdf"
echo In file:%source%
echo Look for anchor:%pdf%
rem Process each line in %source% file:
for /F "usebackq delims=" %%c in ("%source%") do (
set "line=%%c"
REM Test if the line contains pdf file I look for:
SET "pdfline=!line:%pdf%=!"
if not "!pdfline!" == "!line!" (
cls
echo Line: !line!
REM Test if the pdfline contains tag b
SET "tagline=!pdfline:*><b>=!"
if not "!tagline!" == "!pdfline!" (
cls
echo ACTUAL LINE: !tagline!
REM Remove closing tag b
SET "title=!tagline:</b*=!"
echo TITLE: !title!
pause
)
)
)
pause
BTW:
The html page I work with is here.
So I ask you to help complete/repair line SET "title=!tagline:</b*=!"

Batch Script issue

for deleting files, I will be using the code below to remove the oldest file in the directory and run it every day. It came from the question of mine.
Applying to the original batch script:
SET BACKUPDIR=C:\PATH\TO\BACKUPS
FOR /F %%i IN ('DIR /B /O-D %BACKUPDIR%') DO SET OLDEST=%%i
DEL %BACKUPDIR%\%OLDEST%
Something such as that checks if the file amount is 21, if so delete the latest one:
SET BACKUPDIR=C:\test
SET countfiles = dir BACKUPDIR /b | find /v /c "::"
if countfiles > 21
FOR /F %%i IN ('DIR /B /O-D %BACKUPDIR%') DO SET OLDEST=%%i
DEL %BACKUPDIR%\%OLDEST%
EDIT: Sorry for forgetting the question, my attempt was failing, I would be greatful for any way to direct how to make it work.
first, it seems set does not like spaces between the variable and the = sign: if you put a space, the variable name will include a space. so you must remove the space to properly define the variable name.
plus, your syntax for capturing the output of the command into a variable is wrong. the only way i am aware of (after desperately searching stackoverflow for the answer) is to use a for loop trick to use a temporary variable (see this question for more details). actually, you also need to escape the pipe for the command to be parsed correctly.
then, when the variable tested in the if expression does not exists, the results is always true, so make sure the variable exists. by removing the space as said above, the name in the if expression will match your variable name, and the test will execute properly.
then you forgot to make a block around the 2 last commands. actually, you are testing if you have more than 21 files and compute the oldest if it is true, then you ALWAYS delete the oldest.
also, the greater than operator > may be understood as a redirection. you may need to use the GTR operator.
SET BACKUPDIR=C:\test
FOR /F %%i in ('dir BACKUPDIR /b ^| find /v /c "::"') DO SET countfiles=%%i
if countfiles GTR 21 (
FOR /F %%i IN ('DIR /B /O-D %BACKUPDIR%') DO SET OLDEST=%%i
DEL %BACKUPDIR%\%OLDEST%
)
That's not working...you can't set 'normal' variables within a for-loop. I had the same problem some days ago and solved it with this blog entry.
Basically, you need to set SETLOCAL ENABLEDELAYEDEXPANSION and then use ! instead of %...
set FILES=
for /f %%a IN (‘dir /b *.txt’) do set FILES=!FILES! %%a
echo %FILES%
So, this should work for you:
SETLOCAL ENABLEDELAYEDEXPANSION
SET OLDEST=
FOR /F %%i IN ('DIR /B /O-D %BACKUPDIR%') DO SET OLDEST=%%i
DEL %BACKUPDIR%\%OLDEST%

Resources