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
Related
I have a BAT script that counts the number of files in a folder and exports the results into a .txt. It works great, but I'm in a situation where I need to subtract 1 from the value it's currently counting. How could I alter my script to do that?
#echo off
FOR /D %%G in ("*") DO (
PUSHD "%%G"
FOR /F "delims=" %%H in ('dir /a-d /b * ^|find /C /V ""') DO echo %%G %%H>>"..\count.txt"
POPD
)
Your goal is to use %%H with the SET /A command to do the Arithmetic. I chose to use %%G as part of the DIR command. This way you do not need PUSHD and POPD. I also chose to use an IF command to make sure the count is not zero so that it does not substract 1.
I moved the redirection of the output at the end because this opens the file for writing once instead of every time it writes a directory to the output.
The CALL command and the double percent symbols on the variable allows us to use the variable without having to enable delayed expansion.
#echo off
(FOR /D %%G in ("*") DO (
FOR /F "delims=" %%H in ('dir /a-d /b "%%G\*" 2^>NUL ^|find /C /V ""') DO (
IF NOT "%%H"=="0" SET /A "count=%%H-1"
CALL echo %%G %%count%%
)
))>count.txt
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
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 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.
Is it possible to do this?
In a folder i have files with same initial names
Example:
Main folder
-Quest2323231.txt
Quest2343434.txt
Quest2343435.txt
Fund103.txt
Fund102.txt
I have a config file (abc.config) in which i have name of file on which i need to count and move them . If the count is more than 2 then i need to move them.
In this case for e g I need to find files which have name as 'Quest'
Appreciate you help on this.
#echo off
setlocal enableextensions
set "number="
for /f "tokens=1" %%a in (
'dir /a-d /-c "c:\mainfolder\quest*" 2^>nul^|findstr /b /c:" "'
) do if not defined number set "number=%%a"
if not defined number set "number=0"
echo %number%
Untested: This expects text in the first line of abc.config which is the file information such as Quest in the example and if there are more than 2 matching files in the source folder then it will echo a move command to move them to the target folder.
Change *%file%* to %file%* in two places if you want to match only the start of the filename.
Remove the echo to actually perform the move commands.
#echo off
set "source=c:\mainfolder"
set "target=d:\target\folder"
set /p "file=" < "abc.config"
for /f %%a in ('dir /b /a-d "%source%\*%file%*" ^|find /i "%file%" 2^>nul^|find /c /v "" ') do set "number=%%a"
if %number% GTR 2 for /f "delims=" %%a in ('dir /b /a-d "%source%\*%file%*" ^|find /i "%file%" ') do (
echo move "%source%\%%a" "%target%"
)
pause