I need to sort a series of images into folders by part of their names.
The only thing consistent is a series of numbers after an underscore.
I would like to use the content before the underscore as the folder name.
The problem is that some of the images have an underscore in the name.
I'm just not getting the variables right...
Currently using:
#echo off
setlocal enabledelayedexpansion
for %%A in (*.jpg) do (
echo file found %%A
for /f "delims=" %%B in ("%%A") do set fname=%%~nB
for /f "delims=" %%C in ("%%A") do set fextn=%%~xC
for /f "tokens=1* delims=_" %%D in ("!fname!") do set folname=%%D
echo folder name !folname!
if not exist "!folname!" (
echo Folder !folname! does not exist, creating
md "!folname!"
) else (
echo Folder !folname! exists
)
echo Moving file %%A to folder !folname!
move "%%A" "!folname!"
)
echo Finished
pause
Examples of problematic names:
a_t_r_a_v__a_83563614_2994781403891160_6736610473828214002_n.jpg
alexa_vn10s1ty429_81834750_1570208686488587_1442450484794514255_n.jp
More common names:
shurra.m.lance_96141088_342661823370490_6342263806980952485_n.jpg
anu.m0111_104134441_573701159868969_589828829350351913_n.jpg
Currently hoping to get these turned into folders as:
a_t_r_a_v__a
alexa_vn10s1ty429
shurra.m.lance
anu.m0111
Just not getting it to ignore the right underscores.
Thanks for your time in advance. I am learning so much here but I guess I'm just missing the last piece.
This is not a trivial task, but I think I have found a solution (see all the explanatory rem remarks):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem /* Loop through matching files; `findstr` additionally filters them, so only
rem items containing an underscore followed by a decimal digit are processed;
rem exclamation marks are prohibited in the portion behind the prefix: */
for /F "delims= eol=|" %%F in ('
dir /B /A:-D-H-S "*_*.jpg" ^| findstr /RIC:"[^_]_[0123456789][^!]*\.jpg$"
') do (
rem // Store current file name:
set "FILE=%%F" & set "TEST=%%F"
rem // Toggle delayed expansion to avoid problems with exclamation marks:
setlocal EnableDelayedExpansion
rem // Define ascending and descending number sequences for the next loop:
for %%J in ("0,1,9" "9,-1,0") do (
rem // Loop through all decimal digits, increasing, then decreasing:
for /L %%I in (%%~J) do (
rem // Find `_` plus the current digit, remove everything in front:
if not "!TEST:*_%%I=!"=="!TEST!" set "NAME=!TEST:*_%%I=_%%I!"
)
rem /* Remove previously end of file name to get the desired prefix
rem (at this point exclamation marks could cause problems): */
for /F "delims= eol=|" %%E in ("!NAME!") do set "TEST=!TEST:%%E=!"
)
rem // Create desired directory and move current file into it:
ECHO md "!TEST!" 2> nul
ECHO move /Y "!FILE!" "!TEST!\"
endlocal
)
endlocal
exit /B
After having tested for the correct output, remove the upper-case ECHO commands.
This is a simpler (and faster) method:
#echo off
setlocal EnableDelayedExpansion
set "digits=0123456789"
for %%A in (*.jpg) do (
set "fname=%%A"
rem Initialize "first digit after an underscore"
set "firstDigit="
rem Split name at underscores
for %%a in ("!fname:_= " "!") do (
if not defined firstDigit (
set "part=%%~a"
rem Check if first char in part is in "digits"
for /F %%b in ("!part:~0,1!") do if "!digits:%%b=X!" neq "%digits%" set "firstDigit=%%b"
)
)
rem Split name at "underscore+firstDigit"
for /F %%a in ("!firstDigit!") do for /F %%b in ("!fname:_%%a= !") do set "folname=%%b"
echo Moving file %%A to folder !folname!
)
Output example:
Moving file a_t_r_a_v__a_83563614_2994781403891160_6736610473828214002_n.jpg to folder a_t_r_a_v__a
Moving file alexa_vn10s1ty429_81834750_1570208686488587_1442450484794514255_n.jp to folder alexa_vn10s1ty429
Moving file shurra.m.lance_96141088_342661823370490_6342263806980952485_n.jpg to folder shurra.m.lance
Moving file anu.m0111_104134441_573701159868969_589828829350351913_n.jpg to folder anu.m0111
Related
I started using batch commands last week and I've reached a real obstacle with a script I made.
What I want to do
Move a PDF file from C:\Users\JK\Documents\reports PDFs into pre-made subfolders in the destination W:\Departments\QA\cases.
For example the script would move 2223 report.pdf to W:\Departments\QA\cases\2201 - 2300\2223
What I tried
I made a script based off the answer in this thread
cls
#pushd %~dp0
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "SourceDir=C:\Users\JK\Documents\reports PDFs"
set "DestDir=W:\Departments\QA\cases\"
for /F "eol=| delims=" %%A in ('dir /B /A-D-H "%SourceDir%\*.pdf" 2^>nul') do (
for /F "eol=| tokens=1" %%B in ("%%~nA") do (
for /D %%C in ("%DestDir%\%%B*") do move /Y "%SourceDir%\%%A" "%%C\"
)
)
endlocal
popd
pause
Where I am stuck
How could I add subfolders or account for them in the destination directory?
FYI, I also tried adding a wildcard symbol at the end of the destination directory by changing %DestDir%\%%B to %DestDir%\*\%%B*.
I would probably accomplish the task with the following script (see all the explanatory rem remarks):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=C:\Users\JK\Documents\reports PDFs" & rem // (source directory; `.` or `` is current, `%~dp0.` is script parent)
set "_TARGET=W:\Departments\QA\cases" & rem // (target directory; `.` or `` is current, `%~dp0.` is script parent)
set "_SUBDIR=#" & rem // (set to non-blank value in order to create individual sub-directories)
set "_FMASK=????*.pdf" & rem // (pattern to match source files)
set "_DMASK=???? - ????*" & rem // (pattern to match target directories)
set "_FFIL1=^[0123456789][0123456789][0123456789][0123456789] .*\.pdf$" & rem // (filter 1 for source files)
set "_FFIL2=^[0123456789][0123456789][0123456789][0123456789]\.pdf$" & rem // (filter 2 for source files)
set "_DFIL1=^[0123456789][0123456789][0123456789][0123456789] - [0123456789][0123456789][0123456789][0123456789] .*$"
set "_DFIL2=^[0123456789][0123456789][0123456789][0123456789] - [0123456789][0123456789][0123456789][0123456789]$"
rem // Change into source directory:
pushd "%_SOURCE%" && (
rem // Iterate through all files matching the specified pattern and filters:
for /F "eol=| delims=" %%F in ('
dir /B /A:-D-H-S "%_FMASK%" ^| findstr /I /R /C:"%_FFIL1%" /C:"%_FFIL2%"
') do (
rem // Store full path of currently iterated file:
set "FILE=%%~fF"
rem // Extract the leading numeric part of the file name:
for /F "eol=| delims= " %%N in ("%%~nF") do (
rem // Store the numeric part:
set "NUM=%%N"
rem /* Remove any leading zeros from the numeric part of the file name, because
rem such cause the number to be unintentionally interpreted as octal: */
set /A "INT=0" & for /F "eol=| tokens=* delims=0" %%Z in ("%%N") do 2> nul set /A "INT=%%Z"
)
rem // Change into target directory:
pushd "%_TARGET%" && (
rem // Iterate through all directories matching the specified pattern and filters:
for /F "eol=| delims=" %%D in ('
cmd /V /C 2^> nul dir /B /A:D-H-S "!_DMASK:|=%%I!" ^| findstr /I /R /C:"%_DFIL1%" /C:"%_DFIL2%"
') do (
rem // Store name of currently iterated directory:
set "TDIR=%%D"
rem // Extract first (from) and second (to) numeric parts of directory names:
for /F "eol=| tokens=1-2 delims=- " %%S in ("%%D") do (
rem // Remove any leading zeros from first (from) numeric part:
set /A "FRM=0" & for /F "eol=| tokens=* delims=0" %%Z in ("%%S") do set /A "FRM=%%Z"
rem // Remove any leading zeros from second (to) numeric part:
set /A "TOO=0" & for /F "eol=| tokens=* delims=0" %%Z in ("%%T") do set /A "TOO=%%Z"
)
rem // Toggle delayed variable expansion to avoid trouble with `!`:
setlocal EnableDelayedExpansion
rem /* Do integer comparisons to check whether the numeric part of the file name
rem lies within the range given by the directory name (from/to): */
if !INT! geq !FRM! if !INT! leq !TOO! (
rem // Numeric part of file name lies within range, hence try to move file:
if defined _SUBDIR (
2> nul md "!TDIR!\!NUM!"
ECHO move "!FILE!" "!TDIR!\!NUM!\"
) else (
ECHO move "!FILE!" "!TDIR!\"
)
)
endlocal
)
rem // Return from target directory:
popd
)
)
rem // Return from source directory:
popd
)
endlocal
exit /B
You may need to adapt a few constants to your situation in the section commented with Define constants here: at the top.
After having tested the script for the correct output, remove the upper-case ECHO commands in front of the move commands! In order to avoid multiple 1 file(s) moved. messages, replace these ECHO commands by > nul.
I have a folder with files that are (ideally) sequentially named. But sometimes I want to add a new file into the sequence, which I do by appending a letter, so that it still sorts in the right order, e.g.
I want a batch that renames these back into a proper sequence, i.e. P01.svg, P02.svg, P03.svg, etc. Of course, the correct order must be preserved in the process.
I've tried various things, but can't find a solution that preserves the order... sometimes the renaming appears to be done in the wrong order so that the files get out of sequence. My latest attempt is:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
REM first rename with xxx prefix to avoid name clashes, then do a second loop to remove the xxx prefix
set /a i=1
for /f "delims=" %%a in ('dir *.svg /b /a-d-h-s') do (
set "p=0!i!"
ren "%%a" "xxxP!p:~-2!.svg"
set /a i = i + 1
)
REM second loop...
set /a i=1
for /f "delims=" %%a in ('dir *.svg /b /a-d-h-s') do (
set "p=0!i!"
ren "%%a" "P!p:~-2!.svg"
set /a i = i + 1
)
Why are the renamed files not in the correct order every time?
You don't need you first loop. A simple ren command is sufficient.
For the correct order (by name), just expand the dircommand with the /on option ("Order by Name")
#echo off
setlocal enabledelayedexpansion
ren *.svg *.svg.tmp
set nr=100
for /f "delims=" %%a in ('dir /b /a-d-h-s /on *.svg.tmp') do (
set /a nr+=1
ECHO ren "%%a" "P!nr:~-2!.svg"
)
Note: I disabled the ren command for security reasons. When the output fits your needs, just remove the ECHO
You do not need to use two loops and neither do you have to rename the files twice. If you simply count the number of files in advance and then rename then in descending order (hence from highest to lowest) there should not be any collisions possible, given that the files have got consecutive numbers (no gaps allowed).
Here is a script that does exactly this (see all the explanatory rem remarks in the code):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=" & rem /* (root directory; empty or `.` is current,
rem `%~dp0.` is location of this script) */
set "_PREF=P" & rem // (desired file name prefix)
set "_MASK=%_PREF%*.svg" & rem // (search pattern for files)
set /A "_DIGS=2" & rem // (number of digits in the new names)
rem // Get limit of number of files that can be handled:
set /A "CNT=1" & for /L %%D in (1,1,%_DIGS%) do set /A "CNT*=10"
rem // Change into root directory:
pushd "%_ROOT%" && (
rem // Count number of matching files, quit if there are too many:
for /F %%C in ('dir /B /A:-D-H-S "P*.svg" ^| find /C /V ""') do (
set /A "CNT+=%%C" & if %%C geq %CNT% exit /B 2
)
rem /* List files sorted in descending order by name and prepend
rem with an ascending index number: */
for /F "tokens=1* delims=:" %%E in ('
dir /B /A:-D-H-S /O:-N "P*.svg" ^| findstr /N "^"
') do (
rem /* Split off the index number and determine the new number
rem to be used in the new file name: */
set /A "FNUM=CNT-%%E+1"
rem // Store the current file base name and extension:
set "FILE=%%~nF" & set "FEXT=%%~xF"
setlocal EnableDelayedExpansion
rem // Actually rename the file:
ECHO ren "!FILE!!FEXT!" "!_PREF!!FNUM:~-%_DIGS%!!FEXT!"
endlocal
)
popd
)
endlocal
exit /B
After having tested for the correct output, remove the upper-case ECHO command!
This is an approved variant that can even handle collisions (meaning a file with a new name already exists), which may occur when there are gaps in the original (numeric) sequence of file names; in such cases, an additional suffix .tmp is temporarily appended and after having processed all files that suffix becomes removed by a single ren command:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_ROOT=" & rem /* (root directory; empty or `.` is current,
rem `%~dp0.` is location of this script) */
set "_PREF=P" & rem // (desired file name prefix)
set "_MASK=%_PREF%*.svg" & rem // (search pattern for files)
set "_SUFF=.tmp" & rem // (temporary suffix to handle collisions)
set /A "_DIGS=2" & rem // (number of digits in the new names)
rem // Get limit of number of files that can be handled:
set /A "CNT=1" & for /L %%D in (1,1,%_DIGS%) do set /A "CNT*=10"
rem // Change into root directory:
pushd "%_ROOT%" && (
rem // Terminate if there are files with the temporary suffix:
if defined _SUFF if exist "%_MASK%%_SUFF%" popd & exit /B 3
rem // Count number of matching files, quit if there are too many:
for /F %%C in ('dir /B /A:-D-H-S "P*.svg" ^| find /C /V ""') do (
set /A "CNT+=%%C" & if %%C geq %CNT% popd & exit /B 2
)
rem /* List files sorted in descending order by name and prepend
rem with an ascending index number: */
for /F "tokens=1* delims=:" %%E in ('
dir /B /A:-D-H-S /O:-N "P*.svg" ^| findstr /N "^"
') do (
rem /* Split off the index number and determine the new number
rem to be used in the new file name: */
set /A "FNUM=CNT-%%E+1"
rem // Store the current file base name and extension:
set "FILE=%%~nF" & set "EXTF=%%~xF" & set "EXTT="
setlocal EnableDelayedExpansion
rem /* Actually rename the file; in case of collisions, append
rem another suffix to the name and rename again later: */
set "NAME=!_PREF!!FNUM:~-%_DIGS%!!EXTF!"
if /I not "!FILE!!EXTF!"=="!NAME!" (
if exist "!NAME!" set "EXTT=!_SUFF!"
ECHO ren "!FILE!!EXTF!" "!NAME!!EXTT!"
)
endlocal
)
rem // Resolve potential collisions, so remove additional suffixes:
setlocal EnableDelayedExpansion
if defined _SUFF if exist "!_MASK!!_SUFF!" ren "!_MASK!!_SUFF!" "*."
endlocal & popd
)
endlocal
exit /B
Again remove the upper-case ECHO command to actually rename files!
I have a lot of csv file into a folder.
The files are named like OPERATORS_*.csv where * is a variable.
I want, using a batch file, to merge all files into one, delete the first row of each file and add at the end of each row the *.
I have tried this code:
copy /b OPERATORS_*.csv OPERATORS_FULL.csv
This way is fine, but the first row of each file is printed and i lost the attribute in the filename.
Example:
OPERATORS_ACTIVITY1.csv
OPT;SALES;REDEMPTION
OPT1;12;75
OPERATORS_ACTIVITY2.csv
OPT;SALES;REDEMPTION
OPT2;22;64
and i want this:
OPERATORS_FULL.csv
OPT1;12;75;ACTIVITY1
OPT2;22;64;ACTIVITY2
Any suggestions?
Try this (Update #2):
#ECHO OFF
SETLOCAL EnableDelayedExpansion
IF EXIST OPERATORS_FULL.csv DEL OPERATORS_FULL.csv
IF EXIST OPERATORS_FULL.tmp DEL OPERATORS_FULL.tmp
FOR %%A IN ( OPERATORS_*.csv ) DO (
:: get attribute from filename
SET "attr=%%A"
SET "attr=!attr:OPERATORS_=!"
SET "attr=!attr:.csv=!"
:: get date suffix
SET tmp=!attr:_= !
FOR %%G IN ( !tmp! ) DO (
SET date_=%%G
)
:: if we have a date (i.e. a numeric value)
IF !date_! EQU +!date_! (
:: ...remove date from attr with leading underscore
CALL SET attr=%%attr:_!date_!=%%
) ELSE (
:: ...else clear date variable
SET date_=
)
:: dump CSVs, skipping each header line, adding the attribute from the filename
FOR /F "skip=1 tokens=*" %%G IN ( %%A ) DO ECHO %%G;!attr!;!date_! >> OPERATORS_FULL.tmp
)
REN OPERATORS_FULL.tmp OPERATORS_FULL.csv
Here is a different approach using redirection -- see all the explanatory rem remarks in the script:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_INPUT=OPERATORS_*.csv" & rem // (input files)
set "_OUTPUT=OPERATORS_FULL.csv" & rem // (output file)
set /A "_SKIP=1" & rem // (number of lines to skip for each input file)
rem // Redirect the whole output at once:
> "%_OUTPUT%" (
rem // Iterate over all the input files:
for %%F in ("%_INPUT%") do (
rem // Store the current file name to get the attribute name later:
set "NAME=%%~nF"
rem // Exclude the output file from being processed:
if /I not "%%~nxF"=="%_OUTPUT%" (
rem // Determine the number of lines of the current input file:
for /F %%E in ('^< "%%~F" find /C /V ""') do set /A "CNT=%%E"
rem // Read current input file:
< "%%~F" (
setlocal EnableDelayedExpansion
rem // Loop over every line:
for /L %%E in (1,1,!CNT!) do (
rem // Read current line:
set "LINE=" & set /P LINE=""
rem // Return current line if it is not to be skipped:
if %%E GTR %_SKIP% echo(!LINE!;!NAME:*_=!
)
endlocal
)
)
)
)
endlocal
exit /B
#echo off
setlocal
del operators_full.csv 2>nul >nul
FOR %%f IN (operators_*.csv) DO for /f "usebackqdelims=" %%a in ("%%f") do echo %%a>operators_full.txt&goto body
:body
(
FOR %%f IN (operators_*.csv) DO FOR /f "tokens=1*delims=_" %%s IN ("%%~nf") DO for /f "skip=1usebackqdelims=" %%a in ("%%f") do echo %%a;%%t
)>>operators_full.txt
move operators_full.txt operators_full.csv
First, delete the output file if it exists, then start copying the file(s) to a .txt file but deliberately abort after the very first line.
then, for each file, tokenise on the _ in the name part of the file %%f copy every line,appending the post-_ part of the filename in %%t, skipping the first and append to the .txt file (note the position of the outer pair of parentheses - this syntax allows the output of the entire code block to be redirected)
Finally, move or rename the file.
Oh -- you don't want the header line? Omit the first for line.
Couldn't find an answer that wasn't very specific to someone else's problem.
I'd like to place a bat file in a directory and run it to achieve the following:
Replace all initial '-' (hyphen) with ' - ' (space-hyphen-space)
Replace any 3 char Month names (Jan,Feb,...Dec) with two-digit month number preceeded and followed by a hyphen ('Jan' = '-01-' , 'Mar' = '-03-')
So the following:
32432492-2015Jan23-2015Feb23.pdf
32432492-2015Feb24-2015Mar24.pdf
32432492-2015Mar25-2015Apr29.pdf
becomes:
32432492 - 2015-01-23 - 2015-02-23.pdf
32432492 - 2015-02-24 - 2015-03-24.pdf
32432492 - 2015-03-25 - 2015-04-29.pdf
I'd like the "rename" to only run once (instead of renaming all files over and over). It should do this for all files in current directory (except the current bat file of course).
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir\t w o"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*-*" '
) DO (
SET "newname=%%a"
FOR %%b IN ("Jan=-01-" "Feb=-02-" "Mar=-03-" ) DO SET "newname=!newname:%%~b!"
FOR /f "tokens=1*delims=-" %%b IN ("!newname!") DO SET "newname=%%b - %%c"
IF /i NOT "!newname!"=="%%a" ECHO(REN "%sourcedir%\%%a" "!newname!"
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I expect that you would have the sense to complete the month/number set in the form given.
The required REN commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(REN to REN to actually rename the files.
Revision
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir\t w o"
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*-*" '
) DO (
SET "newname=%%a"
FOR %%b IN ("Jan=/01/" "Feb=/02/" "Mar=/03/" ) DO SET "newname=!newname:%%~b!"
FOR /f "tokens=1,2*delims=-" %%b IN ("!newname!") DO SET "newname=%%b - %%c - %%c"
IF /i NOT "!newname!"=="%%a" ECHO REN "%sourcedir%\%%a" "!newname:/=-!"
)
GOTO :EOF
You said "Replace all initial '-' (hyphen) with ' - ' (space-hyphen-space)" which I took to mean "the initial hyphen in the name".
I've got bunch of text files with some content. First I wanted to number the lines globally. Then I extracted all lines that are duplicated somewhere (occur in any of given files at least twice). But now I need to mark all of these lines with the filename and line number of the first occurrence of this line. And now the funny part - it needs to be a windows batch file, using native windows tools. That's why I've got this problem to begin with.
So, to sum it up:
I have a file A with unique strings/lines, each of them is said to occur at least twice in given set of files.
I need to search these files and mark all occurrences of given line from A file with
-file name in which the line first occured
-line number in this file
This is my code with effort to number lines and format files.
#echo off
setlocal EnableDelayedExpansion
set /a lnum=0
if not [%1]==[] pushd %1
for /r %%F in (*.txt) do call :sub "%%F"
echo Total lines in %Files% files: %Total%
popd
exit /b 0
:Sub
set /a Cnt=0
for /f %%n in ('type %1') do (
set /a Cnt+=1
set /a lnum=!lnum!+1
echo ^<!lnum!^> %%n >> %1_ln.txt && echo ^<!lnum!^> >> %1_ln.txt && echo. >> %1_ln.txt
)
set /a Total+=Cnt
set /a Files+=1
echo %1: %Cnt% lines
#echo off
setlocal EnableDelayedExpansion
set lnum=0
if not "%~1" == "" pushd %1
rem "I've got bunch of text files..." (%%F is file name)
for /r %%F in (*.txt) do call :sub "%%F"
echo Total lines in %Files% files: %lnum%
popd
exit /b 0
:Sub "filename"
set Cnt=0
rem "... with some content." (%%n is line contents)
(for /f "usebackq delims=" %%n in (%1) do (
set /a Cnt+=1
rem "First I wanted to number the lines globally."
set /a lnum+=1
echo ^<!lnum!^> %%n
rem "Then I extracted all lines that are duplicated somewhere" (that were defined before)
if defined line[%%n] (
rem "I need to mark all of these lines with the filename and line number of the first occurrence of this line."
echo ^<!line[%%n]!^>
echo/
) else (
REM (Store the first occurrence of this line with *local* line number and filename)
set line[%%n]=!Cnt!: %1
)
)) > "%~PN1_ln.txt"
set /A Files+=1
echo %1: %Cnt% lines
exit /B
The above Batch program ignore empty lines in the input files and fail if they contain special Batch characters, like ! & < > |; this limitation may be fixed if required.
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%s IN (A) DO (
SET searching=Y
FOR /f "delims=" %%f IN (
'dir /s /b /a-d *.txt') DO IF DEFINED searching (
FOR /f "tokens=1delims=:" %%L IN (
'findstr /b /e /n /l /c:"%%s" ^<"%%f"') DO IF DEFINED searching (
ECHO Line %%L IN "%%f" FOUND "%%s"
SET "searching="
)
)
)
Here's the meat of a routine that should do what you appear to be looking for - and that's as clear as mud.
It looks through the "A" file for each string in turn, assigns the string to %%s and sets the flag searching
Then it looks through the file list, assigning filenames to %%f
Then it executes a findstr to find the /c:"%%s" complete string %%s (including any spaces) in /l or literal mode (ie. not using regular expressions) for a line that both /b and /e begins and ends with the target (ie exactly matches) and /n numbers those lines.
The output of findstr will be in the format linenumber:linecontents so if this line is examined by the FORwith the option "delims=:" then the partion up to the first : is assigned to to %%L
So - %%L contains the line#, %%f the filename, %%s the string
Clearing searching having detected this line by setting its value to [nothing] means it's not NOT DEFINED hence no further lines will be reported from the current file, and no further filenames will be examined.
Now if you want to get a listing of ALL of the occurrences of the target lines, all you need to do is to REM-out the SET "searching=" line. Searching will then never be reset, so each line in each file is reported.
If you want some other combination, please clarify.
I have absolutely no idea whatever what you mean by "marking" a line.
#ECHO OFF & setlocal
for /f "tokens=1*delims==" %%i in ('set "$" 2^>nul') do set "%%i="
for %%a in (*.txt) do (
for /f %%b in ('find /v /c "" ^<"%%a"') do echo(%%b lines in %%a.
set /a counter=0, files+=1
for /f "usebackqdelims=" %%b in ("%%~a") do (
set /a counter+=1, total+=1
set "line=%%b"
setlocal enabledelayedexpansion
if not defined $!line! set "$!line!=%%a=!counter!=!line!"
for /f "delims=" %%i in ('set "$" 2^>nul') do (if "!"=="" endlocal)& set "%%i"
)
)
echo(%total% lines in %files% files.
for /f "delims=" %%a in (a) do set "#%%a=%%a"
for /f "tokens=2,3*delims==:" %%i in ('set "$" 2^>nul') do (
if defined #%%k echo("%%k" found in %%i at line %%j.
)
Script can handle !&<>|%, but not =.