Please forgive me if this is glaring obvious but I have the behaviour of this for loop, which loops through certain named directories (US_Site4 etc.) and reads a config file in each of them to run a command separately for each:
setlocal enabledelayedexpansion
REM The Root to start searching from
SET "InstallSets=D:\InstallSets"
REM Folders to not search with in
SET "ExcludeStr=findstr /I /v ^"\Master Files \Training \Software^""
REM
SET "InstallSets=D:\InstallSets"
for /f "delims=*" %%F IN ('dir /s /b /on "!InstallSets!" ^| findstr /E /C:"Config.xml" ^| !ExcludeStr!') do (
(ECHO "%%F"| findstr /I "\US_Site4 \US_Site5" 1>NUL) && (
ECHO "%%F"...
)
)
And I would like to be able replicated in a more user configurable way for furure additions, i.e. settings a variable at the top of a batch file, e.g.:
setlocal enabledelayedexpansion
REM The Root to start searching from
SET "InstallSets=D:\InstallSets"
REM Folders to not search with in
SET "ExcludeStr=findstr /I /v ^"\Master Files \Training \Software^""
REM Folders to search in only
SET "DoOnlyStr=findstr /I ^"\US_Site4 \US_Site5^" 1>NUL"
for /f "delims=*" %%F IN ('dir /s /b /on "!InstallSets!" ^| findstr /E /C:"Config.xml" ^| !ExcludeStr!') do (
(ECHO "%%F"| %DoOnlyStr%) && (
ECHO "%%F"...
)
)
The first one brings back 2 results which are site4 and 5 as expected, however the second one brings back 4 (The 2 I wanted but duplicated). Why is this and how could get a "user friendly" configurable version like just setting the variable? I want to then later make a second file with findstr /I /V to do the opposite and do everything else BUT Site4 and 5.
Kind regards
Adam
It was the 1>NUL that was displaying only the 1 output and when that was in a variable it wasn't behaving as it should, so it was displaying 2 (as it seemed to when I removed it also), But is was a combination of the comment from #aschipfl with removing the " " on the set variables and how I structured it below. So my final solution that worked for me was:
setlocal enabledelayedexpansion
REM The Root to start searching from
SET "InstallSets=D:\InstallSets"
REM Folders to not search with in
SET ExcludeStr=findstr /I /v ^"\Master Files \Training \Software^"
REM Folders to search in only
SET DoOnlyStr=findstr /I ^"\US_Site4 \US_Site5^"
for /f "delims=*" %%F IN ('dir /s /b /on "!InstallSets!" ^| findstr /E /C:"Config.xml" ^| !ExcludeStr!') do (
(ECHO "%%F"| %DoOnlyStr% 1>NUL) && (
ECHO "%%F"...
)
)
Unsure why the !DoOnlyStr! didn't work though and it had to be %DoOnlyStr% as I have setlocal enabledelayedexpansion at the start
Related
I'm trying to pipe a string that contains folder paths to findstr to search for a particular part in the names of the given folders - or at least, that is what I'm planning to do.
I've got a source folder with files that have to be copied into multiple subfolders and after that, one of the copied files has to be renamed corresponding to the destination folder. If there already are files with the same names, they have to be overwritten. I am trying to achieve this via .bat-file using the following commands in my code:
pushd ..\..\destination_folder\
FOR /F "delims=" %%i in ('dir /AD /S /B^| findstr /I "._Modul_X$"') do copy ..\xxx\yyy\ressources\*.* %%i
& ren %%i\xxxx_Modul_X.BAT_TEMPLATE" "%%i_Modul_X.BAT_TEMPLATE
The copy-part seems to work, the rename-part does not and when it comes to overwriting the one file that has to be renamed after copying it (name conflict!), I'm pretty clueless how to do this (IF EXIST & DEL?).
If I understand the process you're attempting, then the following should do as you require, subject to my assumption that xxxx is a sequence of exactly four, digits (directory names), and characters (file names):
#Echo Off
SetLocal EnableExtensions
PushD "..\..\destination_folder" 2>NUL || GoTo :EOF
If Not Exist "..\xxx\yyy\resources\*.*" GoTo :EOF
For /F "Delims=" %%G In (
'Dir /B /S /A:D "????_Modul_X" 2^>NUL ^|%__AppDir__%findstr.exe^
/I /R "\\[0123456789][0123456789][0123456789][0123456789]_Modul_X"'
) Do (
For /F "Delims=" %%H In (
'%__AppDir__%where.exe /F "%%G":"????_Modul_X.BAT_TEMPLATE" 2^>NUL'
) Do Del /A /F %%H
Copy /Y "..\xxx\yyy\resources\*.*" "%%G" 1>NUL
For /F "Delims=" %%I In (
'%__AppDir__%where.exe /F "%%G":"????_Modul_X.BAT_TEMPLATE" 2^>NUL'
) Do If /I Not "%%~nxI" == "%%~nxG%%~xI" Ren %%I "%%~nxG%%~xI"
)
Please note that you will probably need to modify both instances of xxx\yyy\resources, (lines 5 and 14), as nobody really uses names like that, paying special attention to the spelling, I've used resources above, not ressources.
I am new to batch scripting . I need to delete all files in a folder that DOES NOT contains some word in the file
found this code
#echo off
setlocal
pushd C:\Users\admin\Desktop\bat
findstr /ip /c:"importantWord" *.txt > results.txt
popd
endlocal
So how i can WHITE list this files, and delete all other?
Or i think there is easy way with just check if !contains and delete
but i don`t know how?
Supposedly, this problem could be solved in a very simple way combining these findstr switches: /V that show results when the search string is not found, and /M that show just the name of the files; that is:
#echo off
setlocal
cd C:\Users\admin\Desktop\bat
for /F "delims=" %%a in ('findstr /ipvm /c:"importantWord" *.txt') do del "%%a"
Unfortunately, the combination of /V and /M switches don't properly work: the result of /V is based on lines (not files), so a modification in the method is needed:
#echo off
setlocal
cd C:\Users\admin\Desktop\bat
rem Create an array with all files
for %%a in (*.txt) do set "file[%%a]=1"
rem Remove files to preserve from the array
for /F "delims=" %%a in ('findstr /ipm /c:"importantWord" *.txt') do set "file[%%a]="
rem Delete remaining files
for /F "tokens=2 delims=[]" %%a in ('set file[') do del "%%a"
This method is efficient, particularly with big files, because findstr command report just the name of the files and stop searching after the first string match.
#echo off
setlocal
set "targetdir=C:\Users\admin\Desktop\bat"
pushd %targetdir%
for /f "delims=" %%a in ('dir /b /a-d *.txt') do (
findstr /i /p /v /c:"importantWord" "%%a" >nul
if not errorlevel 1 echo del "%%a"
)
popd
endlocal
Not really sure what you want to do with /pfiles - files containing non-ansi characters appear to return errorlevel 1for these. if not errorlevel 1 will echo the files that do not contain the required string - remove the echo to actually delete the file(s)
This should work:
#ECHO OFF
SETLOCAL EnableDelayedExpansion
SET "pathToFolder=C:\FolderToEmpty"
SET "wordToSearch=ImportantWord"
FOR /F "tokens=*" %%F IN ('dir %pathToFolder% /b *.txt') DO (
findstr /IP %wordToSearch% "%pathToFolder%\%%F">nul
IF !ERRORLEVEL!==1 (
DEL /Q "%pathToFolder%\%%F"
)
)
You will have to set the proper path to the folder you want to delete the files from and to replace ImportantWord with the substring you are looking for.
I want to make a script which finds as quickly as possible first folder named Target starting from root location D:\ and return its absolute path.
Folder structure of root location (D:\) can be like this:
-DontSearchHereFolder
-Folder1\Subfolder1\SSubfolder1\SSSubfolder1\
-Folder2\Subfolder2\SSubfolder2\TargetFolder
-DontSearchHereFolder2
-Folder3\Subfolder3\
Output of the script should be: D:\Folder2\Subfolder2\SSubfolder2\TargetFolder
For now I tried 2 methods but it's not quick enough:
(1)
set TG=\TargetFolder
set root=D:\
cd %root%
for /f "delims=" %%a in ('dir /b /s /a:d "%root%" ^|findstr /e /i "%TG%"') do set "folderpath=%%~a"
(2)
for /d /r "%root%" %%a in (*) do if /i "%%~nxa"=="%TG%" set "folderpath=%%a"
(1) is quicker than (2)
Question1: Is it possible to specify in command to search only for a maximum of 2 folders "down" from root (e.g. D:\Folder1\Subfolder1) ?
Question2: Is it possible to specify folders that should be automatically skipped (e.g. DontSearchHereFolder1&2)
This batch code is exactly for what you have asked for optimized for speed. It ignores the two specified directories on first level and it searches for the folders maximal two folder levels deep.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "Root=D:"
set "TG=TargetFolder"
set "Ignore1=DontSearchHereFolder"
set "Ignore2=DontSearchHereFolder2"
for /D %%A in ("%Root%\*") do (
if "%%~nxA" == "%TG%" set "FolderPath=%%A" & goto Found
if not "%%~nxA" == "%Ignore1%" (
if not "%%~nxA" == "%Ignore2%" (
for /D %%B in ("%%A\*") do (
if "%%~nxB" == "%TG%" set "FolderPath=%%B" & goto Found
for /D %%C in ("%%B\*") do if "%%~nxC" == "%TG%" set "FolderPath=%%C" & goto Found
)
)
)
)
echo Could not find folder: "%TG%"
goto EndSearch
:Found
echo Found folder: "%FolderPath%"
:EndSearch
endlocal
The string comparisons are done case-sensitive for maximum speed.
No recursive subroutine calls are used as usually would be done for such tasks for maximum speed.
The comparisons for the directories to ignore in root folder are coded in batch script directly not using an array or a list of folder names for maximum speed.
Delayed expansion is not used for faster processing the command lines.
But much faster would be coding an executable in C/C++/C# for that task as processing the command lines of the batch file takes most likely the most time on searching for the folder.
Note: Command FOR ignores folders with hidden attribute set.
Well, I use for such tasks shareware tool Total Commander which supports searching only in selected folders for a specific folder not more than X levels deep extremely fast.
This should take into account all the limits indicated in the question, but unless a lot of folders are found inside the indicated exclusions, I don't think this should be faster, just give it a try
#echo off
setlocal enableextensions disabledelayedexpansion
set "source=d:\"
set "target=TargetFolder"
set "maxLevels=2"
set excludeFolders= "DontSearchHereFolder" "DontSearchHereFolder2"
for %%s in ("%source%") do for /f "tokens=*" %%f in ('
robocopy "%%~fs." "%%~fs." /l /nfl /njh /njs /nc /ns /s
/xd %excludeFolders% /lev:%maxLevels%
^| findstr /e /i /l /c:"\\%target%\\"
^| cmd /v /q /c"set /p .= &&(echo(!.!)"
') do echo "%%~f"
I think this is the fastest possible way to do this:
#echo off
setlocal EnableDelayedExpansion
if "%1" neq "" goto %1
set "root=D:\"
set "TG=TargetFolder"
set "exclude=/DontSearchHereFolder1/DontSearchHereFolder2/"
"%~F0" Input | "%~F0" Output > result.txt
set /P "folderpath=" < result.txt
del result.txt
echo First folder: %folderpath%
goto :EOF
:Input
cd "%root%"
for /D %%a in (*) do if "!exclude:/%%a/=!" equ "%exclude%" (
cd "%%a"
dir /B /S /A:D "%TG%" 2>NUL
cd ..
)
exit /B
:Output
set /P "folder="
echo "%folder%"
set "i=0"
for /F "tokens=2" %%a in ('tasklist /FI "IMAGENAME eq cmd.exe" /FO TABLE /NH') do (
set /A i+=1
if !i! equ 2 taskkill /PID %%a /F
)
exit /B
The folders to exclude are given in a slash-separated list; if this list is longer, the process run faster because more folders are skipped. The target folder is search in each one of the non-excluded folders via a dir /B /S /AD "%TG%" command, that is faster than any combination of other commands. The process ends as soon as the first folder name is received in the rigt side of the pipe; the remaining processing at left side of the pipe is cancelled via a taskkill command.
I would like to make a .bat file that will open the first file within a random folder/subfolders, in the same location as the .bat file.
The code I currently have only opens a random file.
#echo off
setlocal enableextensions disabledelayedexpansion
set "rootFolder=G:\Movies\Anime"
for /f "usebackq tokens=1,* delims=:" %%a in (`
cmd /q /v /e /c "for /f delims^= %%a in ('dir /a-d /s /b "%rootFolder%"') do echo(!random!:%%a"
^| sort 2^>nul
^| cmd /q /e /v /c "set /p ".^=" & echo(!.!"
`) do start "" "%%~b"
I also have a .bat file that generates a text file with a list of all folders in the same location. I'm not sure if it would be easier to reference that.
dir /b > Animelist.txt
Also if possible how to exclude it opening particular types of files such as jpegs / the other .bat file?
You can try with this
#echo off
setlocal enableextensions disabledelayedexpansion
set "rootFolder=%cd%"
set fileTypes= "*.avi" "*.mpeg" "*.mkv"
pushd "%rootFolder%" && (
for /f "usebackq tokens=1,* delims=:" %%a in (`
cmd /q /v /e /c "set p=&for /r %%a in (%fileTypes%) do if not !f!==%%~dpa (set f=%%~dpa&set /a ((%random% %% 16273^)+1^)*!random!&echo :%%~dpa)"
^| sort 2^>nul
^| cmd /q /e /v /c "set /p ".^=" && echo(!.!"
`) do pushd "%%~b." && (
for /f "delims=" %%c in ('
dir /b /a-d /on %fileTypes% 2^>nul
^| cmd /q /e /v /c "set /p ".^=" && echo(!.!"
') do start "" "%%~fc"
popd
)
popd
)
Decomposing the task in pieces
Configure where to search and what to search (first two set)
Change to the starting folder (pushd)
Execute a recursive search for the indicated file types and output the name of the folder where the file has been found (first cmd inside for /f
As more than one file can be found in the same folder, check that we will not output a duplicate element (if inside first cmd)
For each folder, generate a random number as a prefix (set /a) and output the folder (echo)
Sort the list on the random number (sort)
Get the first folder in the list. As the list is sorted on a random number, this folder has been random selected (second cmd inside for /f %%a)
Discard the random number and retrieve only the folder (the reason for the delims and tokens in the for /f %%a)
Change to the selected folder (pushd)
List the files of the indicated types inside the selected folder (dir)
From this list select only the first file (cmd)
Retrieve the selected file (for /f %%c)
Start the selected file (start)
Return to previous folder (popd)
Return to the starting folder (popd)
The random selection of a folder is unambiguous.
The first video file is a bit more difficult. If using dir with several extensions like #aschipfl suggested, this predetermines which extensions are looked for and found first.
The other way with excluding file types is more tedious without knowing which types might occur.
Here my batch Edited Streamlined some parts:
#echo off
setlocal enableextensions Enabledelayedexpansion
Set Cnt=0
Set "Exclude=.bat$ .cmd$ .jpg$ .jpeg$ .txt$"
Pushd "G:\Movies\Anime"
(Echo::: Numbered List of folders
For /f "delims=" %%F in (
'Dir /B/S/AD/ON'
) Do Set /A Cnt+=1&Echo:!Cnt!:%%F
)>DirList.txt
:: Get Random num 1..Cnt
Set /A RndDir=%Random% %% Cnt+1
:: Get random folder name
For /f "tokens=1,* Delims=:" %%F in (
'Findstr "^%RndDir%:" DirList.txt '
) Do Set "DirName=%%G"
Echo selected %RndDir% of %Cnt% = folder %DirName%
Pushd "%DirName%
Set "FileName"
For /f "Delims=" %%F in (
'Dir /B/A-D ^|findstr /i /V "%Exclude%"'
) Do If Not defined FileName Set "FileName=%%~F"
If defined FileName Start "" "%FileName%"
Popd
Popd
Goto :Eof
I need a command to run from the Windows CLI to identify any folders (or sub folders) that contain only one file. If the folder contains two files, it should not be included. In the end, I need to output this list to a text file. It should contain the full folder path.
Ex: OutputLog.txt
C:\fold1
C:\fold1\sub
C:\fold3
C:\fold4
This should work to identify folders with one file.
#echo off
for /d /r "d:\base\folder" %%a in (*) do (
dir /b /a-d "%%a" 2>nul |find /c /v "" |findstr "^1$" >nul && >>file.txt echo %%a
)
#echo off
setlocal EnableDelayedExpansion
(for /D /R %%a in (*) do (
set count=0
for %%b in ("%%a\*.*") do set /A count+=1
if !count! equ 1 echo %%a
)) > OutputLog.txt
#echo off
set "parentfolder=c:\test"
for /f "tokens=* delims=" %%F in ('dir /s /a:d /b "%parentfolder%"') do (
dir "%%F"|findstr /b "1 File(s)" >nul 2>&1 && echo %%F
)
This will list all subfolders with only one file in a parent folder .As it checks the string of the dir command output it should be altered if language settings/windows version provide different DIR command output.