Use regexp in .BAT to find substring - regex

How can I check contains of substring in string variable of batch file?
for example:
set var1=foobarfoo
set regexp=.*bar.*
if [check var1 by regexp] echo "YES"
In my case, it's must be only check by regular expression and only in .bat file.

Adjusting the answer found here give
#echo off
set var1=foobarfoo
set "regexp=.*bar.*"
echo %var1%
echo %regexp%
setlocal enableDelayedExpansion
echo(%var1%|findstr /r /c:"%regexp%" >nul && (
echo FOUND
rem any commands can go here
) || (
echo NOT FOUND
rem any commands can go here
)

Related

How to subtract string and non-null value entries from txt file?

I have a script that extracts lines such as :
THIS_IS_A_LINE:=
THIS_IS_A_LINE2:=
and outputs all of the same kind into another .txt file as:
THIS_IS_A_LINE
THIS_IS_A_LINE2
The script is the following:
set "file=%cd%/Config.mak"
set /a i=0
set "regexp=.*:=$"
setlocal enableDelayedExpansion
IF EXIST Source_List.txt del /F Source_List.txt
for /f "usebackq delims=" %%a in ("%file%") do (
set /a i+=1
call set Feature[!i!]=%%a
)
cd .. && cd ..
rem call echo.!Feature[%i%]!
for /L %%N in (1,1,%i%) do (
echo(!Feature[%%N]!|findstr /R /C:"%regexp%" >nul && (
call echo FOUND
call set /a j+=1
call set Feature_Disabled[%j%]=!Feature[%%N]:~0,-2!
call echo.!Feature_Disabled[%j%]!>>Source_List.txt
) || (
call echo NOT FOUND
)
)
endlocal
I also have another script that extracts lines such as:
THIS_IS_ANOTHER_LINE:=true
THIS_IS_ANOTHER_LINE2:=true
...
and outputs all of the same kind into another .txt file as:
THIS_IS_ANOTHER_LINE
THIS_IS_ANOTHER_LINE2
...
The script is the following:
set "file=%cd%/Config.mak"
set /a i=0
set "regexp=.*:=true$"
setlocal enableDelayedExpansion
IF EXIST Source_List2.txt del /F Source_List2.txt
for /f "usebackq delims=" %%a in ("%file%") do (
set /a i+=1
call set Feature[!i!]=%%a
)
cd .. && cd ..
rem call echo.!Feature[%i%]!
for /L %%N in (1,1,%i%) do (
echo(!Feature[%%N]!|findstr /R /C:"%regexp%" >nul && (
call echo FOUND
call set /a j+=1
call set Feature_Disabled[%j%]=!Feature[%%N]:~0,-6!
call echo.!Feature_Disabled[%j%]!>>Source_List2.txt
) || (
call echo NOT FOUND
)
)
endlocal
Nevertheless, there is a third kind of lines which contain numerical numbers (also some hexadecimal values), such as:
THIS_IS_AN_UNPROCESSED_LINE:=0xA303
THIS_IS_AN_UNPROCESSED_LINE2:=1943
THIS_IS_AN_UNPROCESSED_LINE3:=HELLO_DOOD_CAN_YOU_PARSE_ME?
So I need the way to extract as well those kind of lines into another .txt file such as:
THIS_IS_AN_UNPROCESSED_LINE:=0xA303
THIS_IS_AN_UNPROCESSED_LINE2:=1943
THIS_IS_AN_UNPROCESSED_LINE3:=HELLO_DOOD_CAN_YOU_PARSE_ME?
So basically extract lines which are not of the kind:
THIS_IS_AN_UNPROCESSED_LINE:=
or
THIS_IS_AN_UNPROCESSED_LINE:=true
but keeping both the sides of the line entry.
I know there must be some trick with the regular expression but I just can't find it out.
You have made your code much more complicated than it needs to be. There is no need to create an array of every line in the file.
If there are no other : or = before the first :=, then you can use FINDSTR to print out all lines that contain a string, followed by :=. FOR /F can capture and parse each matching line into the parts before and after :=, and then IF statements can classify the three different types of lines.
I use n> to open all three output files outside the main code block for improved performance, and then I use the &n> syntax to direct each output to the appropriate, already opened file. I use high numbered file handles to avoid problems described at Why doesn't my stderr redirection end after command finishes? And how do I fix it?.
#echo off
setlocal
set "file=Config.mak"
set /a "empty=7, true=8, unprocessed=9"
%empty%>empty.txt %true%>true.txt %unprocessed%>unprocessed.txt (
for /f "delims=:= tokens=1*" %%A in ('findstr /r "^[^:=][^:=]*:=" "%file%"') do (
if "%%B" equ "" (
>&%empty% (echo %%A)
) else if "%%B" equ "true" (
>&%true% (echo %%A)
) else (
>&%unprocessed% (echo %%A:=%%B)
)
)
)
The above will ignore lines that contain : or = before :=, and it will not work properly if the first character after := is : or =. I'm assuming that should not be a problem.
It should be relatively easy to write a very efficient solution using PowerShell, VBScript, or JScript that eliminates the limitations.
You could also use JREPL.BAT - a powerful and efficient regular expression text processing command line utility. JREPL.BAT is pure script (hybrid batch/JScrpt) that runs natively on any Windows machine from XP onward, no 3rd party exe required. And JREPL is much faster than any pure batch solution, especially if the files are large.
Here is one JREPL solution
#echo off
setlocal
set repl=^
$txt=false;^
if ($2=='') stdout.WriteLine($1);^
else if ($2=='true') stderr.WriteLine($1);^
else $txt=$0;
call jrepl "^(.+):=(.*)$" "%repl%" /jmatchq^
/f Config.mak /o unprocessed.txt >empty.txt 2>true.txt
If all you have to do is classify the lines into three different files, without worrying about stripping off the :=true and := parts for the empty and true lines, then there is a very simple pure batch solution using nothing but FINDSTR.
#echo off
set "file=Config.mak"
findstr /r ".:=$" "%file%" >empty.txt
findstr /r ".:=true$" "%file%" >true.txt
findstr /r ".:=" "%file%" | findstr /r /v ":=$ :=true$" >unprocessed.txt

Windows batch script to search for specific files to delete

I need help converting the following Linux/Mac commands into a Windows batch script.
find / -regex ``^.*/Excel_[a-z]*.xls'' -delete 2>/dev/null
find / -regex ``^.*/presentation[0-9]*[a-z]*.ppt'' -delete 2>/dev/null
Basically using regular expressions, I need to find any of the .xls/.ppt files (in the format above) in a given Windows box and delete them.
Sorry, I'm new to Windows batch files.
You really don't explain what your hieroglypics mean.
In a batch file,
#echo off
setlocal
dir /s "c:\local root\Excel_*.xls"
would show all of the files matching starting Excel_ with extension .xls
(and if that's what you want, simply replacing dir with del would delete them; adding >nul would suppress messages; adding 2>nul suppresses error messages)
If you want files starting Excel_ then followed by any alphas-only, then
for /f "delims=" %%a in ('dir /b /s /a-d Excel_*.xls ^| findstr /E /R "\\Excel_[a-z]*\.xls" ') do echo "%%a"
The dir produces a directory list in /b (basic) form (ie. filename-only) /s - with subdirectories (which attaches the full directory name) and the /a-d suppresses directorynames. This is piped to findstr to filter out the required filenames. The result is assigned to %%a line-by-line, and the delims= means "don't tokenise the data"
should show you all the files matching that criterion - but it would be case-sensitive; add /i to the findstr switches to make it case-insensitive. (/r means "regex" within findstr's restricted implementation; /e means "ends" - I tend to use these over $) The \\ in intended to implement escaped \ to ensure the filename match is complete (ie do't find "some_prefixExcel_whatever.xls) - I'll leave what \. is intended to do to your imagination...
(again, change echo to del to delete and add in the redirection palaver if required)
And the other regex - well, follow the bouncing ball. It would appear you want .ppt files with names starting presentation followed by a possible series of numerics then by a series of alphabetics. I'd suggest
findstr /e /r "\\presentation[0-9]*[a-z]*\.ppt" for that task.
Use PowerShell.
get-childitem | where-object { $_.Name -match '<put a regex here>' } | remove-item
get-childitem returns file system objects, and the where-object filter selects only those file system objects whose name property matches a regular expression. These filtered items are then passed through the pipeline to remove-item.
There is good information about the PowerShell pipeline in the about_pipelines help topic, which you can read using the following command:
help about_pipelines
Plain Batch can't do this task. But you could make use of tools like findstr which come with Windows and support Regex.
This line can be executed from CMD and deletes all files in the current folder which match the RegEx:
for /f "eol=: delims=" %F in ('findstr /r "MY_REGEX_HERE"') do del "%F"
So try to get your expected results by playing around with this command. If your fine with the output/results, you can embed this line in your batch script. (Be careful, when embedding this line in batchscript you have to double the percentage signs!)
for /f "eol=: delims=" %%F in ('findstr /r "MY_REGEX_HERE"') do del "%%F"
Here a small batch to do what you are looking for:
#echo off
set /p dirpath=Where are your files ?
:: set dirpath=%~dp0 :: if you want to use the directory where the batch file is
set /p pattern=Which pattern do you wanna search (use regex: *.xml e.g.) :
:: combinason /s /b for fullpath+filename, /b for filename
for /f %%A in ('dir /s /b "%dirpath%\%pattern%" ^| find /v /c ""') do set cnt=%%A
echo File count = %cnt%
call :MsgBox "Do you want to delete all %pattern% in %dirpath%? %cnt% files found" "VBYesNo+VBQuestion" "Click yes to delete the %pattern%"
if errorlevel 7 (
echo NO - quit the batch file
) else if errorlevel 6 (
echo YES - delete the files
:: set you regex, %%i in batch file, % in cmd
for /f "delims=" %%a in ('dir /s /b "%dirpath%\%pattern%"') do del "%%a"
)
:: avoid little window to popup
exit /b
:: VBS code for the yesNo popup
:MsgBox prompt type title
setlocal enableextensions
set "tempFile=%temp%\%~nx0.%random%%random%%random%vbs.tmp"
>"%tempFile%" echo(WScript.Quit msgBox("%~1",%~2,"%~3") & cscript //nologo //e:vbscript "%tempFile%"
set "exitCode=%errorlevel%" & del "%tempFile%" >nul 2>nul
endlocal & exit /b %exitCode%

Extract number from string in batch file

From a batch file I want to extract the number 653456 from the following string:
C:\Users\testing\AppData\Local\Test\abc123\643456\VSALBT81_COM
The number will change, however it will always be just digits.
My current theory is to search for something that fits \alldigits\, then replace the two \s with white space, but I can’t quite get it.
Assuming the number is always the parent folder (the folder before the end):
#echo off
set "str=C:\Users\testing\AppData\Local\Test\abc123\643456\VSALBT81_COM"
for %%F in ("%str%\..") do set "number=%%~nxF"
EDIT - Code sample adapted to correct errors shown in comments
set d=C:\Users\testing\AppData\Local\Test\abc123\643456\VSALBT81_COM
for %%f in ("%d:\=" "%") do for /f %%n in ('echo %%f^|findstr /b /e /r "\"[0-9]*\""') do (
echo %%~n
)
Just precede the path with a quote, split the path, replacing each backslash with a quote a space and a quote and append a quote (so we have a list of elements to iterate), and for each part check if it is formed only by numbers
#echo off
setlocal EnableDelayedExpansion
set "string=C:\Users\testing\AppData\Local\Test\abc123\643456\VSALBT81_COM"
for /L %%d in (0,1,9) do set "string=!string:\%%d=\ %%d!"
for /F "tokens=2" %%a in ("%string%") do for /F "delims=\" %%b in ("%%a") do echo Number: [%%b]
This uses a helper batch file called repl.bat from - https://www.dropbox.com/s/qidqwztmetbvklt/repl.bat
#echo off
set "string=C:\Users\testing\AppData\Local\Test\abc123\643456\VSALBT81_COM"
echo "%string%"|repl ".*\\([0-9]*)\\.*" "$1"
Here is how I striped numbers from a string in batch (not a file path, should be generically working for a "string")
#ECHO OFF
::set mystring=Microsoft Office 64-bit Components 2013
set mystring=Microsoft 365 Apps for enterprise - en-us
echo mystring = %mystring%
for /f "tokens=1-20 delims=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!##$&*()-= " %%a in ("%mystring%") do (
IF %%a == 64 (
set ONum=%%b
GoTo varset
)
IF %%a == 32 (
set ONum=%%b
GoTo varset
)
set ONum=%%a
)
:varset
echo numfromalphanumstr = %numfromalphanumstr%
pause
https://www.dostips.com/forum/viewtopic.php?t=3499
https://superuser.com/questions/1065531/filter-only-numbers-0-9-in-output-in-classic-windows-cmd
Extract number from string in batch file
How to extract number from string in BATCH

Batch .BAT script to rename files

Im looking for a batch script to (recursively) rename a folder of files..
Example of the rename:
34354563.randomname_newname.png to newname.png
I already dug up the RegEx for matching from the beginning of the string to the first underscore (its ^(.*?)_ ), but cant convince Windows Batch to let me copy or rename using RegEx.
From command-line prompt - without regex:
FOR /R %f IN (*.*) DO FOR /F "DELIMS=_ TOKENS=1,*" %m IN ("%~nxf") DO #IF NOT "%n" == "" REN "%f" "%n"
In batch file, double %:
FOR /R %%f IN (*.*) DO FOR /F "DELIMS=_ TOKENS=1,*" %%m IN ("%%~nxf") DO #IF NOT "%%n" == "" REN "%%f" "%%n"
EDIT: A new pure batch solution issuing following cases:
Path\File_name.ext => name.ext
Path\none.ext (does nothing)
Path\Some_file_name.ext => file_name.ext
Path\name.some_ext (does nothing)
Path\Some_file_name.some_ext => name.some_ext
Batch (remove ECHO to make it functional):
FOR /R %%f IN (*.*) DO CALL :UseLast "%%~f" "%%~nf"
GOTO :EOF
:UseLast
FOR /F "DELIMS=_ TOKENS=1,*" %%m IN (%2) DO IF "%%n"=="" (
IF NOT "%~2"=="%~n1" ECHO REN %1 "%~2%~x1"
) ELSE CALL :UseLast %1 "%%n"
GOTO :EOF
avoid _ in the extension:
#ECHO OFF
FOR /F "DELIMS=" %%A IN ('DIR /S /B /A-D *_*.*') DO FOR /F "TOKENS=1*DELIMS=_" %%B IN ("%%~NA") DO IF "%%~C" NEQ "" ECHO REN "%%~A" "%%~C%%~XA"
Look at the output and remove ECHO if it looks good.
The standard windows shell doesn't have regex capabilities, and in fact it's extremely basic. But you can use powershell to do this.
I'm not very familiar with power shell, but this other question explains how to filter files: Using powershell to find files that match two seperate regular expressions
New Solution
There is an extremely simple solution using JREN.BAT, my new hybrid JScript/batch command line utility for renaming files and folders via regular expression search and replace.
Only rename files with one underscore:
jren "^[^_]+_([^_]+\.png)$" "$1" /s /i
Preserve everything after the first underscore:
jren "^.*?_" "" /s /fm "*.png"
Preserve everything after the last underscore:
jren "^.*_" "" /s /fm "*.png"
=========================================================
Original Answer
This can be done using a hybrid JScript/batch utility called REPL.BAT that performs regex search and replace on stdin and writes the result to stdout. All the solutions below assume REPL.BAT is somewhere within your PATH.
I intentionally put ECHO ON so that you get a log of the executed rename commands. This is especially important if you get a name collision: two different starting names could both collapse to the same new name. Only the first rename will succeed - the second will fail with an error message.
I have three solutions that differ only in how they handle names that contain more than 1 _ character.
This solution will only rename files that have exactly one _ in the name (disregarding extension). A name like a_b_c_d.txt would be ignored.
#echo on&#for /f "tokens=1,2 delims=*" %%A in (
'2^>nul dir /b /s /a-d *_* ^| repl ".*\\[^_\\]*_([^_\\]*\.[^.\\]*)$" "$&*$1" a'
) do ren "%%A" "%%B"
The next solution will preserve the name after the last _. A name like a_b_c_d.txt would become d.txt
#echo on&#for /f "tokens=1,2 delims=*" %%A in (
'2^>nul dir /b /s /a-d *_* ^| repl ".*_([^\\_.]*\.[^.\\]*)$" "$&*$1" a'
) do echo ren "%%A" "%%B"
This last solution will preserve the name after the first _. A name like a_b_c_d.txt would become b_c_d.txt. This should give the same result as the Endoro answer.
#echo on&#for /f "tokens=1,2 delims=*" %%A in (
'2^>nul dir /b /s /a-d *_* ^| repl ".*\\[^\\]*?_([^\\]*\.[^.\\]*)$" "$&*$1" a'
) do echo ren "%%A" "%%B"

batch file: if %variable% (commands)

i want to use my %variable% to manage the conditional clauses in a IF.. THEN.. ELSE in a batch file.
Something like the following:
set variable=%%homedrive%% EQU C:
if %variable% (
echo test ok
) else (
echo test fail
)
if i write on a cmd console:
set test=1 equ 1
if %test% echo OK
it works!
i'll use it in a for /f cicle:
this is my pseudo codethis is my pseudo code to correct
(
rem echo "%systemdrive%;;"
echo "%%COMPUTERNAME%% EQU [x];[some parameters1]"
echo "%%USERNAME%% NEQ [y];[some parameters2]"
echo "%%LOGONSERVER%% EQU [z];[some parameters3]"
[..]
) > "%temp%\CSG_fs.tmp"
[..]
for /f "usebackq tokens=1-2* delims=;" %%a in ("%temp%\CSG_fs.tmp") do (
set cond=%%a& set cond=!cond:~1!
set parm=%%b& set parm=!parm:~0,-1!
echo - cicle: "!cond!" --^> "!parm!"
call if !cond! call:CSG_sub_fs !parm!
echo - done
)
goto:eof
:CSG_sub_fs
[..]
goto:eof
--edit--
how can i use the variable !cond! to decide if execute the call to CSG_sub_fs?
call if !cond! call:CSG_sub_fs !parm!
does not work because it returns: "Can not find the batch label specified - IF"
and if i use
if !cond! call:CSG_sub_fs !parm!
it will say: "call:CSG_sub_fs not expected"
Well - there doesn't seem to be a question, so it's not that easy to answer.
You have a problem with
echo "^%COMPUTERNAME^% EQU [x];[some parameters1]"
because ^ does not escape % - % escapes % - use %%COMPUTERNAME%%...
(you should have been able to check this just by TYPEing "%temp%\CSG_fs.tmp"
Next problem is that
for /f "tokens=1-2* delims=; usebackq" %%a in (%temp%\CSG_fs.tmp) do (
may process the file %temp%\CSG_fs.tmp provided %temp%\CSG_fs.tmp contains no spaces, semicolons or commas. If it contains any of these deafult separators, or certain other characters with a special meaning, then you must enclose the filename in double-quotes "%temp%\CSG_fs.tmp"and use the usebackq option.
You've attempted to use usebackq but DELIMS must be the LAST option if it is used. Your code would set ";","","u","s","e","b","a","c","k" and "q" as delimiters.
Beyond that, perhaps if you explain what you intend to achieve, we'd be able to devise the appropriate code.
Try this:
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
CLS
REM I'm setting these variables for testing.
REM That isn't ususally a good idea but the SETLOCAL
REM will ensure they are restored on exit
SET computername=[x]
SET logonserver=[z]
(
rem echo "%systemdrive%;;"
echo "%%COMPUTERNAME%% EQU [x];[some parameters1]"
echo "%%USERNAME%% NEQ [y];[some parameters2]"
echo "%%LOGONSERVER%% EQU [z];[some parameters3]"
) > "%temp%\CSG_fs.tmp"
for /f "usebackqtokens=1-2* delims=;" %%a in ("%temp%\CSG_fs.tmp") do (
set cond=%%a& set "cond=IF !cond:~1! CALL :csg_sub_fs "
set parm=%%b& set parm=!parm:~0,-1!
CALL :varcmd "!cond!" "!parm!"
)
GOTO :eof
:varcmd
%~1 %~2
GOTO :eof
:csg_sub_fs
ECHO parameters supplied to csg_sub_fs were: %*
GOTO :eof
I've forced the variablenames to match the conditions you've used in order to trigger the subroutine calls. Change as you need to prove your concept.
And dont worry about imperfect English. I'm sure I wouldn't do as well in your language!