I could use some help, I've tried similar topics but I couldn't find exactly what I was looking for.
What I need is a batch script which loops through a directory searching for files of type .pro but don't begin with the character {.
The script then searches all the files and echoes the lines which are found between the numbers 574, and 575,.
I've got all the things done except when I try to check for file names I cant get it to work properly and it seems so simple.
My script looks like this:
#echo off
set "sPath=C:\Users\jspajic\Desktop\batskripte\test\test files"
set "ispis=C:\Users\jspajic\Desktop\batskripte\test\Opera_procesi_DataTabovi.txt"
echo %sPath% > %ispis%
pushd %sPath%
for %%f in (*.pro) do ( :: ---> I guess this part needs to be altered
setlocal enabledelayedexpansion
for /f "delims=]" %%a in ('findstr /n /B "574," "%%f"') do (set s=%%a )
if !s! neq 0 (
for /f "delims=]" %%b in ('findstr /n /B "575," "%%f"') do (set kraj=%%b)
if !kraj! neq 0 (
#set /a "ss=s+1"
#set /a "kraj=kraj+0"
#set /a "s=s+0"
if !ss! NEQ !kraj! (
#echo:
echo %%f
#set /a "counter=1"
for /F "tokens=1* delims=:" %%A in ('type "%%f" ^| findstr /n "^"') do (
if !counter! GTR !s! if !counter! LSS !kraj! echo.%%B
#set /a "counter=counter+1"
)
)
)
)
endlocal
) >> %ispis%
popd
I tried with for /f "delims=" %%a in ('dir /B *.pro^|findstr "[A-z]*\.pro" ')
or with similar ideas but I cant get it to work cause I just dont know batch scripts that well.
for %%f in (*.pro) do ( set "dummy=%%f"
setlocal enabledelayedexpansion
if "!dummy:~0,1!" neq "{" (
should solve your problem. Note that it adds an extra level of parentheses, so a matching ) needs to be added after the endlocal but you seem to be adept at doing that.
Assign the filename to a dummy variable, then see whether the 1st character of that dummy is NOT equal to "{" before executing the rest of the code.
From the prompt, set /? will show documentation about substringing - you seem to have delayed expansion worked out.
Because your character does not have a case, (upper | lower), and your search directory is already current; this can be easily catered for using EOL in your For loop:
For /F "EOL={Delims=" %%f In ('Dir/B/A-D *.pro') Do (
use for /f with dir, filtered by findstr (eliminate every token that starts with {):
for /f "delims=" %%f in ('dir /b /a-d *.pro^|findstr /vb "{"') do (
Related
I have a batch which scans a directory structure and gives out the size of directorys I defined he should look for.
E.g. the directory '10XXX' contains the subdirectorys '10001', '10002' and '10003'. Now lets say that the batch should look for the dir 'XYZ' in those subdirs. Result is a .csv with informations like '10001\XYZ' 100 Bytes; '10002\XYZ' 2000 Bytes; '10003\XYZ' 0 Bytes.
The problem is the batch scans every directory every time it runs, which takes a lot of time and resources.
My idea is to implement a section into the code that everytime the batch starts scanning a dir it takes a look into a .txt (for example) and when the dir name is found in that file the batch skips the dir.
This is maybe not the most effective solution, but it will take less time and resources than scanning every dir every time.
So different ideas are of course welcome.
Unfortunately I have not enough knowledge to do it myself so I hope that someone could help me.
Code:
#echo off &setlocal
set /p rootfolder=<Enter_Directory_Path_Here.txt
set /p savefolder=<Enter_Save_Directory_Here.txt
set "batpath=%~dp0"
pushd "%rootfolder%"
for /d %%i in (*) do (
set "foldername=%%~nxi"
set "folder=%%i"
>"%batpath%%%~nxi.csv" type nul
for /f "delims=" %%j in ('dir /ad /b "%%i\*"') do (
set "subfolder=%%j"
call :procfolder
)
>"%batpath%%%~nxi.~csv" type nul
for /f "usebackq tokens=1* delims==" %%j in ("%savefolder%\patterns.txt") do (
>>"%batpath%%%~nxi.~csv" findstr /b %%k "%batpath%%%~nxi.csv"
if errorlevel 1 >>"%batpath%%%~nxi.~csv" echo "%%j";"not found"
)
>nul move /y "%batpath%%%~nxi.~csv" "%batpath%%%~nxi.csv"
)
popd
call :cleaner
exit /b
:procfolder
setlocal
for /f "tokens=3" %%i in ('dir /a /-c "%folder%\%subfolder%\"^|findstr /c:"Datei(en)"') do >>"%batpath%%foldername%.csv" echo "%subfolder%";%%i;"Bytes"
for /f "delims=" %%i in ('dir /ad /b "%folder%\%subfolder%\"') do (
set "subfolder=%subfolder%\%%i"
call :procfolder
)
endlocal
exit /b
A sample of reading a text file to match
for /F "tokens=*" %%X in (N:\SomeDirectory\SomeFile.txt) do if /I "%foldername%" EQU "%%X" goto SKIPIT
REM Do your normal stuff here
:SKIPIT
If the exclusion filename is encapsulated in quotes, add the usebackq option:
for /F "usebackq tokens=*" %%X in ("N:\Some Directory\Some File.txt") do if /I "%foldername%" EQU "%%X" goto SKIPIT
REM Do your normal stuff here
:SKIPIT
I'm using window OS, and I downloaded video as series lesson. I would like order those videos by date and adding prefix number for first video as 1 than 2, 3..... I found answer at here How to rename and add incrementing number suffix on multiple files in Batch Script? it can add number to filename, but can only order by name not date. Thank and sorry for my English.
Here is a simple implementation of what aschipfl suggested in his comment:
#echo off
setlocal enableDelayedExpansion
set /a n=0
for /f "delims=" %%F in ('dir /b /od') do (
set /a n+=1
ren "%%F" "!n!_%%F"
)
But there are two potential problems:
1) The FOR /F command has a default EOL character of ; - if a file name were to start with ;, then it would be skipped. The simple solution is to set EOL to a character that cannot appear in a file name - : is a good choice.
2) The rename will fail if a filename contains a ! character because delayed expansion is enabled, and %%F is expanded before delayed expansion. The solution is to save the file name to a variable, and then toggle delayed expansion ON and OFF within the loop
#echo off
setlocal disableDelayedExpansion
set /a n=0
for /f "eol=: delims=" %%F in ('dir /b /od') do (
set "file=%%F"
set /a n+=1
setlocal enableDelayedExpansion
ren "!file!" "!n!_!file!"
endlocal
)
There is a simpler option - use FINDSTR /N to prefix the DIR /B /OD output with the line number, and then use FOR /F to parse out the number and the file name. Now there is no need for a counter variable or delayed expansion.
#echo off
for /f "delims=: tokens=1*" %%A in ('dir /b /od ^| findstr /n "^"') do ren "%%B" "%%A_%%B"
You don't even need a batch file. You could use the following directly from the command line:
for /f "delims=: tokens=1*" %A in ('dir /b /od ^| findstr /n "^"') do ren "%B" "%A_%B"
I have a folder full of text files that I need to split based on the (optional) presence of a delimiter. I found an answer for how to actually split the file here: Split text file into 2 files by separator
#echo off&setlocal
set "file=_frmCore.frm"
for /f "delims=[]" %%i in ('^<"%file%" find /n "SearchTermHere"') do set "split=%%i"
(for /f "tokens=1*delims=[]" %%i in ('^<"%file%" find /n /v ""') do if %%i lss %split% echo(%%j)>"%file%.new1"
<"%file%">"%file%.new2" more +%split%
type "%file%.new?"
Works great for what it is, but I need a few refinements and not sure where to start. Looking for:
Wrap it in a loop for all files in the directory (no subfolders to worry about)
"SearchTermHere" is the first on a line (the only on a line), with a specific term on the previous line that I'd rather match for safety... how can I tell it "PreviousLine/r/nSearchTermHere/r/n"? Unsure of the correct syntax here.
Rather than creating two new files, move the "after search term" portion to a new file and remove it from the original
Parameterize folder name to operate in so I can call from other programs
(apologies... I've tried deciphering this code and finding out what does what and trying to go from there, but this stuff is not my cup of tea and a strong push in the right direction would be wonderful)
#ECHO OFF >NUL
SETLOCAL enableextensions
rem enabledelayedexpansion
set "_files=*.frm"
set "_sfind=SearchTermHere"
if not "%~1"=="" if exist "%~1\" (
pushd "%~1"
set "_popd=popd"
) else ( set "_popd=" )
for /F "delims=" %%G in ('findstr /m "^%_sfind%$" %_files%') do (
type NUL > "%%G.new1"
type NUL > "%%G.new2"
for /f "delims=:" %%i in ('findstr /n "^%_sfind%$" "%%G"') do (
for /f "tokens=1* delims=:" %%I in ('findstr /n "^" "%%G"') do (
if %%I lss %%i (
>> "%%G.new1" echo(%%J
)
if %%I gtr %%i (
>> "%%G.new2" echo(%%J
)
)
)
rem remove `ECHO` from next line no sooner than debugged!
ECHO move /Y "%%G.new1" "%%G"
type "%%G.new?"
)
%_popd%
Changes made in your code:
Wrap it in a loop for all files in the directory: see for /F "delims=" %%G loop against all files matching your criteria: findstr /m "^%_sfind%$" %_files%.
"SearchTermHere" is the first on a line (the only on a line): ^=beginning of line and $=end of line in findstr /m "^%_sfind%$" %_files%; used findstr command rather than find.
Rather than creating two new files, move the "after search term" portion to a new file and remove it from the original: see the move /Y "%%G.new1" "%%G" workaround. Operational move command is ECHOed here merely for debugging purposes. Remove ECHO from that line no sooner than debugged!
Parameterize folder name to operate in so I can call from other programs:
call "batch path\31749577.bat" "folder path"
see %~1 test: if a parameter is supplied to the batch and represents a folder, (more in Command Line arguments (Parameters)) and
see pushd - popd pair: PUSHD changes the current directory/folder and store the previous folder/path for use by the POPD command.
The tricky <"%%G">"%%G.new2" more +%%i command substituted with less effective but clear to understand if %%I gtr %%i ( ... inside the %%I loop. However, next code snippet (entire %%G loop) will work as well:
for /F "delims=" %%G in ('findstr /m "^%_sfind%$" %_files%') do (
for /f "delims=:" %%i in ('findstr /n "^%_sfind%$" "%%G"') do (
>"%%G.new1" (for /f "tokens=1* delims=:" %%I in ('
findstr /n "^" "%%G"') do if %%I lss %%i echo(%%J)
<"%%G">"%%G.new2" more +%%i
)
rem remove `ECHO` from next line no sooner than debugged!
ECHO move /Y "%%G.new1" "%%G"
type "%%G.new?"
)
Excuse me. Although your description is extensive, it is also confusing. The Batch file below:
Search for a line that is "SearchTermHere".
If the previous line is "PreviousLine":
Move from line after SearchTerm up to end of file to another file
Repeat previous process on all files in folder.
.
#echo off
setlocal EnableDelayedExpansion
set "find=SearchTermHere"
set "prevLine=PreviousLine"
rem Process the folder given in parameter
cd %1
rem Process all files in folder
for /F "delims=" %%F in ('dir /A-D /B') do (
rem Get the line number of the search line - 1
set "numLines="
for /F "delims=:" %%a in ('findstr /N "^%find%$" "%%F"') do set /A "numLines=%%a-1"
if defined numLines (
rem Open a code block to read-input-file/create-output-file
< "%%F" (
rem Copy numLines-1 lines
for /L %%i in (1,1,%numLines%) do (
set "line="
set /P "line="
echo(!line!
)
rem If the line before search is prevLine
if "!line!" equ "%prevLine%" (
rem Copy just the search line to original file
set /P "line="
echo !line!
rem and copy the rest of lines to another file
findstr "^" > "%%~nF-PART2%%~xF"
)
) > "%%F.tmp"
if exist "%%~nF-PART2%%~xF" (
rem Replace original file with created output file (first part)
move /Y "%%F.tmp" "%%F" > NUL
) else (
rem Remove the output file
del "%%F.tmp"
)
)
)
For a further explanation of this method, see this post.
Sorry, I was unable to use either of the proposed solutions. However they did help - I spent the last two days learning about the (odd) syntaxes and operations involved in batch files and came up with the following. It doesn't do quite everything that I was looking for (and I altered the program that outputs the files a bit for further support), but it does get the job done:
#ECHO off
setlocal EnableDelayedExpansion
:: change the working directory to match the input
cd /D %~d1
cd %~p1\
:: loop all .frm files and find the CodeBehindForm string
for %%F in (*.frm) do (
for /F "delims=[]" %%a in ('^<%%F find /n "CodeBehindForm"') do (
if %%a gtr 0 (
for /F "tokens=1*delims=[]" %%i in ('^<"%%F" find /n /v ""') do if %%i gtr %%a echo(%%j)>>"%%~nF.vb"
for /F "tokens=1*delims=[]" %%i in ('^<"%%F" find /n /v ""') do if %%i lss %%a echo(%%j)>>"%%~nF.fwm"
:: if the codebehind was found and parsed out, there's a .fwm and .vb file
:: remove the original
if exist %%~nF.vb del %%F
)
)
:: change the .fwm extensions back to their original .frm extensions
ren *.fwm *.frm
I'm sure it's not "correct" in many ways, but for now it gets the job done.
Thanks for the help.
I work with hundreds of thousands of folders/files, most of which have certain log files. It takes a lot of time to manually navigate through the folders to grab the logs, so Ive been using a script to do it.
Its a 2 parter. First part runs overnight to parse all of the directories (they change daily and new logs are added very often, so I index everything nightly to keep the index current).
This first part is automatic and I never touch it, it just runs nightly. Output goes to a txt file, which is used when I execute the second script.
Second script is where I put in keywords of what log I am looking for. This script relies on the txt output from the first script to quickly locate the file and pull it down.
(The reason I do it this way is because its a 5 second task to parse 300,000 line text file looking for a file, and its a 15-30 minute job to search (index all of the network shares). This way I can get my logs in 5 seconds and not 30+ minutes).
Prior to last week the log directories consisted of about 5000 files and folders. This past weekend IT switched over to a new system, and it is now consisting of over 500,000 files and folders. They dumped archives, and a bunch of other files in there that I do not need.
First script used to index it in about 10-15 minutes (its a network share, actually 4 network shares), no problem overnight. While now this is a 4+ hour feat. I need to be able to exclude certain directories during indexing thereby reducing the 500,000 file/folder count back down to under 5,000.
Ive been using this command to index:
dir /b /-d /-p /s /A:-D > C:\output.txt
I need have the indexing skip any directory containing the words "Common" or "Old" in them, and potentially others as well. The goal is to save time by not going inside of these directories at all.
I tried looking into PowerShell to do this, but I know nothing about it.
I need the output to be in the following format:
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\dbInstaller.exe
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\DisplayDriver.nvi
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\DisplayDriverExt.dll
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\license.txt
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\mcu.ex_
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvae.inf
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvak.inf
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvapi.dl_
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvapi64.dl_
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvcompiler.dl_
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvcompiler32.dl_
C:\NVIDIA\DisplayDriver\GeForce332.21Driver\Display.Driver\nvcplsetupeng.exe
Thanks!
#ECHO OFF
SETLOCAL
SET "sourcedir=."
(
FOR /f "delims=" %%a IN (
'dir /b /s /ad "%sourcedir%\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO ( FOR /f "delims=" %%b IN ('dir /b /a-d "%%a" 2^>nul') DO ECHO(%%a\%%b
)
)>newfile.txt
GOTO :EOF
I used a file named q22903564.txt containing exclusion words for my testing.
Produces newfile.txt.
Naturally, choice of sourcedir, q22903564.txt and newfile.txt are all in your court...
#ECHO OFF
SETLOCAL
:: make a tempfile
:maketemp
SET "tempfile=%temp%\%random%"
IF EXIST "%tempfile%*" (GOTO maketemp) ELSE (ECHO.>"%tempfile%a")
SET "sourcedir=."
:: get a dir listing from the root
(
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO (ECHO("%%~fa")
)>"%tempfile%b"
:again
(
FOR /f "usebackqdelims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /ad "%%~a\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO FOR /f "delims=" %%c IN ('ECHO("%%~a\%%b"^|findstr /x /v /i /l /g:"%tempfile%b"') DO ECHO "%%~c"
)
)>"%tempfile%c"
FOR %%a IN ("%tempfile%c") DO SET /a sizec=%%~za
IF %sizec% gtr 0 TYPE "%tempfile%c">>"%tempfile%b"&GOTO again
(
FOR /f "usebackqdelims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /a-d "%%~a\*" 2^>nul'
) DO ECHO(%%~a\%%b
)
)>newfile.txt
DEL "%tempfile%*"
GOTO :eof
Well - need to charge you extra for doing what, according to some, is impossible.
#ECHO OFF
SETLOCAL
:: make a tempfile
:maketemp
SET "tempfile=%temp%\%random%"
IF EXIST "%tempfile%*" (GOTO maketemp) ELSE (ECHO.>"%tempfile%a")
SET "sourcedir=."
:: get a dir listing from the root
(
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO (ECHO("%%~fa")
)>"%tempfile%b"
SET /a sizec=0
:again
SET "skipcnt=usebackq"
IF %sizec% gtr 0 (
FOR /f %%a IN ('type "%tempfile%b" ^|find /c /v ""') DO SET "skipcnt=usebackqskip=%%a"
TYPE "%tempfile%c">>"%tempfile%b"
)
(
FOR /f "%skipcnt%delims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /ad "%%~a\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO FOR /f "delims=" %%c IN ('ECHO("%%~a\%%b"^|findstr /x /v /i /l /g:"%tempfile%b"') DO ECHO "%%~c"
)
)>"%tempfile%c"
FOR %%a IN ("%tempfile%c") DO SET /a sizec=%%~za
IF %sizec% gtr 0 GOTO again
(
FOR /f "usebackqdelims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /a-d "%%~a\*" 2^>nul'
) DO ECHO(%%~a\%%b
)
)>newfile.txt
DEL "%tempfile%*"
GOTO :eof
Third time's a charm. This version works out how many lines of directory it's already processed and skips those lines when re-processing the concatenated lists b and c. IOW, it only processes the additions.
And in typing this, I've realised there's another little simplification... have to wait for morning tea, though...
#ECHO OFF
SETLOCAL
:: make a tempfile
:maketemp
SET "tempfile=%temp%\%random%"
IF EXIST "%tempfile%*" (GOTO maketemp) ELSE (ECHO.>"%tempfile%a")
SET "sourcedir=."
:: get a dir listing from the root
(
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO ECHO(%%~fa
)>"%tempfile%c"
SET /a sizec=0
:again
SET "skipcnt=usebackq"
IF %sizec% neq 0 FOR /f %%a IN ('type "%tempfile%b" ^|find /c /v ""') DO SET "skipcnt=usebackqskip=%%a"
TYPE "%tempfile%c">>"%tempfile%b"
(
FOR /f "%skipcnt%delims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /ad "%%a\*" ^|findstr /v /i /l /g:q22903564.txt'
) DO ECHO(%%a\%%b
)
)>"%tempfile%c"
FOR %%a IN ("%tempfile%c") DO SET /a sizec=%%~za
IF %sizec% gtr 0 GOTO again
(
FOR /f "usebackqdelims=" %%a IN ("%tempfile%b") DO (
FOR /f "delims=" %%b IN (
'dir /b /a-d "%%a\*" 2^>nul'
) DO ECHO(%%a\%%b
)
)>newfile.txt
DEL "%tempfile%*"
GOTO :EOF
This time for sure! (no lion's roar thought)
I realised that the re-filtering against the original tempfileb content was redundant - and removing that meant that the quoting regime to overcome awkward characters could be scaled back. Then in reality the original file was the original addition (tempfilec) to an empty tempfileb, so - a little reorganisation and hand-waving (because 'skip=0' is invalid) and the result is that the only directories that are scanned later are thos that have beed added in the last iteration, optimising the directory-scan methodology.
Now the consequences are that the resultant list will be \a\, \b\, \c\, \a\a1\, \b\b1\, and so on - but a simple sort of the result should take care of that, if required.
This may help: it excludes the terms in line 3 where you see "Common Old"
It creates a list of the folders, filters out the excluded terms, and uses the remaining folders to create the list.
If you only want *.log *.txt files etc then it could be made more efficient again - otherwise remove the *.log *.txt terms in the batch file in line 7
#echo off
dir /b /ad /s /-p > "C:\output.txt"
findstr /v /i "Common Old" "C:\output.txt" >"C:\output2.txt"
del "C:\output.txt"
for /f "usebackq delims=" %%a in ("C:\output2.txt") do (
pushd "%%a"
for /f "delims=" %%b in ('dir *.log *.txt /b /-p /a-d') do >>"C:\output.txt" echo(%%a\%%b
popd
)
I was having an issue with creating a batch file (.bat) to rename multiple files in the same directory based on specific parameters. In order to make it happen for multiple files I had to add an incremental value to it.
From research(mostly here) I pieced together the below command, but whatever I do I cannot actually get to do it. It just echos what's supposed to do and when I remove the echo from before 'ren' it says bad syntax.
#echo off
CD C:\FolderPath\
setlocal enabledelayedexpansion
set /a count=0
for /f "tokens=*" %%a in ('dir /b /od *.txt') do (
echo ren CDFF_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%hr%%time:~3,2%%time:~6,2%%time:~9,2%_!count!.txt
set /a count+=1
)
Add the first parameter to ren command (the file to rename):
ren "%%a" "CDFF_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%hr%%time:~3,2%%time:~6,2%%time:~9,2%_!count!.txt"
So the whole code is:
#echo off
setlocal enabledelayedexpansion
CD C:\FolderPath\
set /a count=0
for /f "tokens=*" %%a in ('dir /b /od *.txt') do (
echo ren "%%a" "CDFF_%date:~-4,4%%date:~-10,2%%date:~-7,2%_%hr%%time:~3,2%%time:~6,2%%time:~9,2%_!count!.txt"
set /a count+=1
)
Please note it will not work for files with weird names. Eg. "File( name.txt"
ren requires the input filname as its first argument. Hence your syntax error.
Here is an alternative implementation:
#echo off
setlocal enabledelayedexpansion
set FOLDER=%1
set DATE=%date:~-4,4%%date:~-10,2%%date:~-7,2%_%hr%%time:~3,2%%time:~6,2%%time:~9,2%
set /a count=0
for /r %FOLDER% %%a in (*.txt) do (
ren "%%a" CDFF_%DATE%_!count!.txt
set /a count += 1
)
call as
rename.bat C:\FolderPath