Batch - Find string in text file and delete full line - string

I use the script from this Thread accepted answer from Mofi. The script copy folders and store them in text file to exclude once copied folders on next run.
Sometimes I have folders called [incomplete]-different.names and I do not want to copy this folders. I want that all folders with the string [incomplete]- and the name behind are skipped or are not even written in the text file %CurrentList% for further processing.
These are my previous attempts but so far I could not get up and running with the script from the top.
Help would be nice, and thanks in advance.
Try 1:
for /f "delims=" [incomplete]-%%D in ("%CurrentList%") do (
set str=%%D
set str=!str: =!
set str=!str: %%D =!
echo !str!
Try 2:
findstr /v /b /c:"[incomplete]-"%%D" "%CurrentList%" del "%%D"

You were really close with your second attempt.
If all you want is to delete lines in %CurrentList% that contain the string [incomplete]-, you can just direct the output of a findstr /v to a temp file and then overwrite CurrentList with that file.
findstr /v /c:"[incomplete]-" "%CurrentList%" >tmpList.txt
move /y tmpList.txt "%CurrentList%" >nul

Related

How to loop through a directory and skip folders containing a specific string?

I am currently scanning an entire directory, copying an exe over and running it in each folder. This exe converts certain log files within each folder. However, half the directories don't contain any log files and it seems like a waste to move into each of those folders and run an exe that does nothing. An example of some folder names:
0075D-S10
0075D-S10-EVT
0132C-S10
0132C-S10-EVT
and so on...
I basically only need to copy the executable into the folders that don't contain EVT in the name. These just contain evtx files that aren't important to me at the moment.
Here is a snippet of my batch file and what it is doing:
set back=%cd%
set current_dir=%cd%
setlocal EnableDelayedExpansion
for /d %%i in ("%current_dir%\*") do (
copy LogCsv.exe "%%i" >NULL
cd "%%i"
LogCsv.exe
)
cd %back%
Really my first time just using Batch files and I've been exploring answers on here, but couldn't find a solution to this particular problem. How can I loop this directory, excluding any folders containing the "EVT" string in their name?
Thanks for taking time to assist!
Well, you can use findstr /v to exclude certain values from search results.
#echo off
set back=%cd%
set current_dir=%cd%
for /f %%i in ('dir /b /ad %current_dir%\* ^| findstr /v EVT') do (
copy LogCsv.exe "%%i" >NUL
cd "%%i"
LogCsv.exe
cd %back%
)
Also note, you need to pipe to nul not null

Setting a variable from a string inside a TXT file with a batch file

I'm attempting to create a batch file for my company's users to use to migrate files from their older 'personal folder' network share to our new OneDrive implementation.
The problem is, some of our users have change the default sync folder for OneDrive to whatever drive and path they wanted, instead of keeping the default (*c:\users\username*)...for example, the one I'm using to test my BAT file against is using:
D:\OneDrive - Business
However, it does still have to work when it contains more or less delimiters, like C:\OneDrive or C:\This Is Where I Foolishly Store Stuff.
At this point, I've tried using REG QUERY to output to a text file from the UserFolder key in the registry to get the path, and now I'm trying to extract this path FROM the text file in question and set it to a variable. The text file that is created looks like the following:
HKEY_CURRENT_USER\SOFTWARE\Microsoft\OneDrive\Accounts\Business1
UserFolder REG_SZ D:\OneDrive - Business
What I want to do is set the "D:\OneDrive - Business" to a variable to use in a scripted MOVE command.
My code is so awful, that I will refrain from posting it unless someone decides its necessary to answer my question.
I'm sure that for at least a DOZEN of you, this is child's play, so I would really appreciate any help that is provided me!!!
Thanks!!
Here is one batch solution for this task:
#echo off
for /F "skip=1 tokens=1,2*" %%A in ('%SystemRoot%\System32\reg.exe QUERY HKCU\SOFTWARE\Microsoft\OneDrive\Accounts\Business1 /v UserFolder 2^>nul') do if /I "%%A" == "UserFolder" if not "%%C" == "" set "UserFolder=%%C" & goto UserFolderSet
echo No user folder for OneDrive found in Windows registry.
goto :EOF
:UserFolderSet
echo Found user folder: "%UserFolder%"
Better readable is this version doing exactly the same:
#echo off
for /F "skip=1 tokens=1,2*" %%A in ('%SystemRoot%\System32\reg.exe QUERY HKCU\SOFTWARE\Microsoft\OneDrive\Accounts\Business1 /v UserFolder 2^>nul') do (
if /I "%%A" == "UserFolder" (
if not "%%C" == "" (
set "UserFolder=%%C"
goto UserFolderSet
)
)
)
echo No user folder for OneDrive found in Windows registry.
goto :EOF
:UserFolderSet
echo Found user folder: "%UserFolder%"
The command FOR executes the command REG in a background command process with capturing its output written to handle STDOUT.
An error message output by REG to handle STDERR is suppressed by redirecting it to device NUL because of 2^>nul. The redirection operator > is escaped with caret character ^ which is necessary to interpret > first as literal character by Windows command interpreter on parsing the FOR command line. But later on execution of REG command line with 2>nul by FOR > is interpreted as redirection operator. An error message could occur if the registry value does not exist at all in Windows registry.
FOR processes each non empty line of captured output of REG command by splitting the line up into substrings (tokens) using space and tab as delimiter (default).
The option skip=1 instructs FOR to skip the first line of captured output.
The option tokens=1,2* instructs FOR that first space/tab delimited string being here value name UserFolder should be assigned to first loop variable A.
The second space/tab delimited string being here type REG_SZ should be assigned to loop variable B being the next character in ASCII table. Now it should be clear why loop variables are case-sensitive while environment variables are not case-sensitive. This loop variable is not further processed here although it might be good in case of type is REG_EXPAND_SZ instead of REG_SZ as in this case the directory path contains most likely also 1 or more environment variable references which must be expanded before having real directory path.
The string after the spaces/tabs after second space/tab delimited string being in your example D:\OneDrive - Business should be assigned without further splitting up on spaces/tabs to loop variable C because of * after 2 in options string tokens=1,2*.
The first IF condition makes sure the right line is processed as on Windows XP the output of REG starts with a header where only the first line would be skipped.
The second IF condition makes sure the user folder value has a non empty value.
The string of interest is finally assigned to environment variable UserFolder and the FOR loop is exited with a jump to the commands below label UserFolderSet.
The commands below the FOR loop are executed if the registry value was not found in Windows registry.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
for /?
goto /?
if /?
set /?
Read also the Microsoft article about Using Command Redirection Operators.
Perhaps:
For /F "EOL=H Tokens=2*" %%A In ('Reg Query "HKCU\SOFTWARE\Microsoft\OneDrive\Accounts\Business1" /V "UserFolder"') Do Set "var=%%B"
Echo(%%var%% = %var%
Pause
I won't use a text file but directly Reg.exe to read the registry value
#Echo off
Set "Key=HKCU\SOFTWARE\Microsoft\OneDrive\Accounts\Business1"
Set "Val=UserFolder"
For /f "Tokens=2* delims= " %%A in (
'Reg query "%Key%" /V %Val% ^|find /i "%Val%" '
) Do Set "%Val%=%%B"
Set %Val%
You can combine the output of the [MSDN]: reg with [MSDN]: findstr (to filter out some useless data), and iterate over what's left using [SS64]: for.
Here's the code (it must be run from a batch file):
#echo off
set _KEY_NAME=HKEY_CURRENT_USER\SOFTWARE\Microsoft\OneDrive\Accounts\Business1
set _VALUE_NAME=UserFolder
set _VALUE_DATA=
for /f "tokens=1,2,*" %%f in ('reg query %_KEY_NAME% /v %_VALUE_NAME% /t REG_SZ 2^>NUL ^| findstr %_VALUE_NAME%') do (
set _VALUE_DATA="%%h"
)
echo Data: %_VALUE_DATA%
This is based on the fact that on my machine (Win10), reg query %_KEY_NAME% /v %_VALUE_NAME% /t REG_SZ (with different values for the _KEY_NAME and _VALUE_NAME), output:
HKEY_CURRENT_USER\SOFTWARE\_DummyKey
_DummyValue REG_SZ D:\OneDrive - Business
End of search: 1 match(es) found.
#EDIT0: After looking at #Mofi's solution, I realized that I had no error handling. Added some.

Batch Move based on filename without Delimiters, String Only

Okay, Windows 7 Enterprise x64 here with a Windows batch file question. I am a somewhat basic user with little knowledge of batch file creation. I've modified existing scripts I've found online to my use, that is about it.
I have a piece of software that dumps it's output to a folder with file names concatenated from the project title, current system date, current system time, and project settings.
It will export two files in this format every time the project is saved:
PROJECTTITLE_2016_10_07__09_45_11__A_B_C.iges
PROJECTTITLE_2016_10_07__09_45_11__A_B_C.step
The A, B, and C representing switches used in the software that are specific to the project. These may exist or may not exist as in the file name can be _R_F or _R_F_Z etc.
"PROJECTTITLE" can literally be anything. This is where my problem arises using delimiters. You could potentially have file names like all of the following (using real examples from users):
11475shacklebody_2016_10_07__09_45_11__R_F.iges
11475shacklebody_2016_10_07__09_45_11__R_F.step
test_EFMflow_2016_10_07__09_45_11__R_Z.iges
test_EFMflow_2016_10_07__09_45_11__R_Z.step
untitled16_2016_10_07__09_45_11__R.iges
untitled16_2016_10_07__09_45_11__R.step
#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.iges
#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.step
prooftestwithoutupperlandsimproved-4_2016_10_07__09_45_11.iges
prooftestwithoutupperlandsimproved-4_2016_10_07__09_45_11.step
What I want to do is move both the IGES and STEP files from the output folder on the C drive to a new folder on a networked drive with name based on "PROJECTTITLE," creating that folder if needed. I have already task scheduled a -delim based batch to run every night, but found delimiters to not be sufficient for my use.
While it seems like an easy job to do with delimiters, looking for the first underscore, I have had projects with underscores in their names that screws up the folder naming. Since delimiters only work for individual characters, not strings, I have been looking for examples of batch files I can adapt to my use with no luck finding any similar to what I want to do that do not use delimiters.
It seems simple, search for string "_2016," in filename, and take all characters before "_2016" and create a new directory, placing files containing those characters in that folder. I am lost as to how to do this without delimiters though.
What I have working so far, using delimiters looking for underscores, creating folders and moving to those folders on a mapped drive:
for /f "delims=_" %%V in ('dir /b /a-d C:\Output\*_*.iges') do (
mkdir "I:\ENG\PARTS\%%V" 2>nul
move "C:\Output\%%V_*.iges" "I:\ENG\PARTS\%%V" >NUL 2>nul
move "C:\Output\%%V_*.step" "I:\ENG\PARTS\%%V" >NUL 2>nul
)
It is a very simple batch file for what it does, but falls flat on it's face with titles containing underscores.
A few things:
Searching for _2016 would mean the batch file would need yearly maintenance. Could we either search for system %YEAR% or somehow search for "_####_##_##_" with something like a regular expression to get away from searching for system date or a specific year?
EDIT:
While not ideal as the switches are useful, I found a way in the software to not export the project specific switches at the end of the file name. So now the export would be:
PROJECTTITLE_2016_10_07__09_45_11.iges
PROJECTTITLE_2016_10_07__09_45_11.step
Which I know I can trim from right, what, 21 characters, use that name to make a folder and search the directory for all files containing that trimmed string.
It still would be nice to figure out how to search for the specific string though with the switches intact. I am willing to learn, so throw all explanations of your code you can at me.
Double (Late) EDIT:
First, thank you all for answering this, I deeply appreciate your help.
Double underscores in the the filename are quite rare, but do happen, probably due to typos. It becomes more of an issue with the volume of files I'm planning to move with this. The software runs on maybe 100 user machines with 20 or so being heavy users, each saving up to maybe 1000 files a day. The software will automatically save in increments, as the user runs the simulation. I'm trying to give them a way to collaborate and view each other's simulation results over the network (that we actively encourage them to use) and it figures that the software is hard coded to output to the C drive (for "performance" as the vendor tells me). I'm looking into scheduling the files to move every 15 minutes on every PC in their OU instead of nightly to give a near-real-time view on what they are working on.
Another option I explored was symbolically linking the output folder on each machine to the software's folder network drive, but found that this really doesn't solve the user's "organization" issue, putting like project runs in the same folder. This also has the issue of not allowing them to save a project out of the office without VPN, which some users do do, then move their files over when they get back in the office.
Thank you for your assistance.
Next batch script should do the job even if a file name contains cmd poisonous characters like space or % percent sign etc.
#ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
set "_fouts=C:\Output" your setting
set "_fouts=D:\test\39924063" my setting
for /F %%G in ('wmic OS get localdatetime ^|find "."') do set "_fyear=%%G"
pushd "%_fouts%"
set "_fyear=%_fyear:~0,4%"
call :doDir
set /A _fyear -= 1
call :doDir
popd
ENDLOCAL
goto :eof
:doDir
rem debugging output echo(%_fyear%
for /f "delims=" %%V in ('
dir /b /a-d "*_%_fyear%_*.iges" "*_%_fyear%_*.step" 2^>NUL') do (
set "_fname=%%~nV" filename without extesion
set "_fexte=%%~xV" extesion only
call :doAll
)
goto :eof
:doAll
call set "_ftail=%%_fname:*_%_fyear%_=%%"
call set "_fproj=%%_fname:_%_fyear%_%_ftail%=%%"
rem debugging output echo("%_fproj%" "%_fname%" "%_fexte%"
ECHO mkdir "I:\ENG\PARTS\%_fproj%" 2>nul
ECHO move "%_fname%%_fexte%" "I:\ENG\PARTS\%_fproj%\"
goto :eof
Output (note that operational mkdir and move commands are merely displayed for debugging purposes using ECHO mkdir and ECHO move, respectively):
==> dir /B /S "D:\test\39924063" /S
D:\test\39924063\#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.iges
D:\test\39924063\#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.step
D:\test\39924063\%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.iges
D:\test\39924063\%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.step
==> D:\bat\SO\39924063.bat
mkdir "I:\ENG\PARTS\#14drop_wire-edm"
move "#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.iges" "I:\ENG\PARTS\#14drop_wire-edm\"
mkdir "I:\ENG\PARTS\%PROJECT TITLE"
move "%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.iges" "I:\ENG\PARTS\%PROJECT TITLE\"
mkdir "I:\ENG\PARTS\#14drop_wire-edm"
move "#14drop_wire-edm_2016_10_07__09_45_11__R_F_Z.step" "I:\ENG\PARTS\#14drop_wire-edm\"
mkdir "I:\ENG\PARTS\%PROJECT TITLE"
move "%PROJECT TITLE_2016_10_07__09_45_11__A_B_C.step" "I:\ENG\PARTS\%PROJECT TITLE\"
==>
Resources (required reading, incomplete):
(command reference) An A-Z Index of the Windows CMD command line
(additional particularities) Windows CMD Shell Command Line Syntax
(%~nV, %~xV etc. special page) Command Line arguments (Parameters)
(set "_fyear=%_fyear:~0,4%" etc.) Extract part of a variable (substring)
(%variable:StrToFind=NewStr% etc.) Variable Edit/Replace
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
REM (
FOR /f "delims=" %%a IN (
'dir /b /a-d "%sourcedir%\*__*" '
) DO (
IF /i "%%~xa"==".iges" CALL :process "%%a"
IF /i "%%~xa"==".step" CALL :process "%%a"
)
REM )>"%outfile%"
GOTO :EOF
:: Process filename "%1"
:process
SET "fullname=%~1"
SET "junk=%fullname:*__=%"
CALL SET "project=%%fullname:%junk%=%%"
SET "project=%project:~0,-13%
ECHO(MD "%destdir%\%project%"
ECHO(MOVE "%sourcedir%\%~1" "%destdir%\%project%\"
GOTO :eof
You would need to change the settings of sourcedir and destdir to suit your circumstances.
The required MD commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MD to MD to actually create the directories. Append 2>nul to suppress error messages (eg. when the directory already exists)
The required MOVE commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MOVE to MOVE to actually move the files. Append >nul to suppress report messages (eg. 1 file moved)
This approach simply performs a directory list without directorynames (/a-d) of each file in the source directory that contains a double-underscore. Each filename matching is assigned to %%a and if the extension part (%%~xa) is one of the targets, then process the filename.
Processing consists of removing all of the characters before the double-underscore and then removing that junk part from the full name, giving project+date. Remove the last 13 characters and you have your project name.
Will have problems with any filename containing certain symbols like % or = but should be fine with underscores.
This version assumes there will not be an instance of _YYYY_ in the PROJECTTITLE.
#Echo Off
SetLocal EnableExtensions DisableDelayedExpansion
(Set OutDir=I:\ENG\PARTS)
(Set SrcDir=C:\Output)
If Not Exist "%SrcDir%\" Exit/B 1
If Not Exist "%OutDir%\" Exit/B 1
For /F "EOL=Y" %%A In ('WMIC Path Win32_LocalTime Get Year') Do (
For /F "Delims=" %%B In ("%%A") Do Set "ThisYr=%%B")
For /F "Delims=" %%A In ('Where "%SrcDir%:*_%ThisYr%_*.iges"') Do (
If Exist "%%~dpnA.step" Call :Sub %%~nA)
Exit/B
:Sub
Set "BigTit=%~1"
For /F "Delims=" %%A In ('CMD /Q /C "Call Echo %%BigTit:_%ThisYr%_=&:%%"') Do (
If Not Exist "%OutDir%\%%A\" MD "%OutDir%\%%A"
Move "%SrcDir%\%~1*.*" "%OutDir%\%%A">Nul)
Edit, there is no need to export without the potentially useful project switches using the above code.
Supposing the PROJECTTITLE part of the file names does not contain two consecutive underscores, you could use the following script, which splits off the first occurrence of __ and everything after (so the time part and the optional switches are removed), using a standard for loop rather than for /F; then it splits off another 11 characters (hence the remaining date part), using sub-string expansion:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=."
set "_TARGET=."
for /F delims^=^ eol^= %%F in ('
pushd "%_SOURCE%" ^&^& ^(
dir /B /A:-D ^
"*_????_??_??__??_??_??*.iges" ^
"*_????_??_??__??_??_??*.step" ^
^& popd^)
') do (
call :PROCESS "%%F"
)
endlocal
exit /B
:PROCESS val_file
setlocal DisableDelayedExpansion
set "FILE=%~1"
setlocal EnableDelayedExpansion
for %%I in ("!FILE:__=";"!") do (
endlocal
set "ITEM=%%~I"
setlocal EnableDelayedExpansion
goto :NEXT
)
:NEXT
if defined ITEM (
set "ITEM=!ITEM:~,-11!"
md "%_TARGET%\!ITEM!" 2> nul
if not exist "%_TARGET%\!ITEM!\!FILE!" (
move /Y "%_SOURCE%\!FILE!" "%_TARGET%\!ITEM!\" > nul
)
)
endlocal
endlocal
exit /B
Finally I come up with a script that is able to handle even files whose PROJECTTITLE part contain __ on their own. It splits off the last occurrence of __ and everything after (so the optional switches are removed, if any, or the time part is removed otherwise), using a standard for loop rather than for /F; then it splits off another 21 characters (hence the remaining date and time parts), or, if no optional switches were present, just another 11 characters (hence the remaining date part), using sub-string expansion:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=."
set "_TARGET=."
for /F delims^=^ eol^= %%F in ('
pushd "%_SOURCE%" ^&^& ^(
dir /B /A:-D ^
"*_????_??_??__??_??_??*.iges" ^
"*_????_??_??__??_??_??*.step" ^
^& popd^)
') do (
call :PROCESS "%%F"
)
endlocal
exit /B
:PROCESS val_file
setlocal DisableDelayedExpansion
set "FILE=%~1"
set "BASE=%~n1"
set "NAME=" & set "ITEM="
setlocal EnableDelayedExpansion
for %%I in ("!BASE:__=";"!") do (
for /F "delims=" %%E in ("!NAME!!ITEM!__") do (
endlocal
set "NAME=%%E"
set "ITEM=%%~I"
setlocal EnableDelayedExpansion
)
)
if defined NAME (
set "NAME=!NAME:~2,-2!"
echo("!ITEM!"| > nul findstr /R "^\"[0-9][0-9]_[0-9][0-9]_[0-9][0-9]\"$" || (
if defined NAME set "NAME=!NAME:~,-10!"
)
if defined NAME set "NAME=!NAME:~,-11!"
if defined NAME (
md "%_TARGET%\!NAME!" 2> nul
if not exist "%_TARGET%\!NAME!\!FILE!" (
move /Y "%_SOURCE%\!FILE!" "%_TARGET%\!NAME!\" > nul
)
)
)
endlocal
endlocal
exit /B

Search for a file and open the path in CMD

I would like to achieve the following in CMD:
Will search for a specific filename - This I know how to do, with dir /s filename
Once found it will bring me to that path.
Example: I am now on C:\, if that file was found in C:\test then it will open C:\test in command prompt.
Alternatively, I would like just to copy the found file to a path I will specify. I just don't know how to do it, since I don't know the path where the file will be stored (it's different every time).
Thanks in advance!
I'm a liitle confused with your question but I will try to walk you through a batch code I wrote to help you with this.
dir /b /s "test.txt" > "%userprofile%/Desktop/result.txt"
::find the file path to the file you want to find and insert it in a .txt file
::you made called result.txt (also %userprofile% is a variable that brings you to
::your user directory ex C:/users/admin)
for /F "tokens=*" %%A in (%userprofile%/desktop/result.txt) do (
set var1=%%A
)
::set the variable var1 equal to the first (well... only) line in the file.
::I could explain what that for loop means in detail but just remember that %%A
::is a variable set from what was found when looping through the result.txt.
xcopy /s "%var1%" "C:/wherever/you/want/it/to/go"
did this help??

I would like a script to search within text files a certain pattern of strings and move those files to another directory

I need to know how to perform an advanced search on a text file using tools like notepad++, freecommander and windows if possible. A bat script file will be great.
The problem is that i need to search through about 1000 txt files in a directory. I need to know form those 1000 txt files which have a string in the form of for example "SYR_SHA/245/4". I just want it search for the pattern for example *****_******/*****/****** where * are characters that can change in number.
There must be an _ between the first and second set of characters as seen above in the example.
the script should go through the entire txt file and search for the above pattern. The script should then Move all the results in to a seperate directory
Many Thanks
Create this batch file and copy it into your folder where you have all the 1000 .txt files
Change the yourdestinationdirectory directory and run the batch file
#Echo Off
FindStr /M /R "[a-zA-Z]*_[a-zA-Z]*\/[0-9]*\/[0-9]*" *.Txt > findstr.out
For /F "tokens=*" %%a In (FindStr.out) Do call :move_Rtns %%a
del FindStr.out
Exit /B
:move_rtns
copy %1 yourdestinationdirectory\*
del /Q %1
Exit /B
Please change the Regex according to your requirement, for eg. If you are expecting number and letter together you can replace [a-zA-z] with [a-zA-Z0-9]
Good luck

Resources