I am looking to create a batch script that will take all image files that are larger than x, compress them in one .zip.
Then take all remaining image files that are less than that same x size and compress them in one .zip
I've tried several, several different ways and can't figure it out. I've searched on here and all mighty Google lol
My latest thoughts are listing the files that are larger in a text file temporarily and then using that list for 7zip to compress them, but can't figure out how to echo/print/list them to 7zip.
#ECHO OFF
SETLOCAL EnableDelayedExpansion
for /f "tokens=2-4 delims=/ " %%a in ('date /t') do (set mydate=%%c-%%a-%%b)
for /f "tokens=1-2 delims=/:" %%a in ("%TIME%") do (set mytime=%%a%%b)
SET FOLDER=%~dp1
REM Sets current directory
SET LOG="log.txt"
pushd %FOLDER%
REM Changes directory to current
for %%a in ("%cd%") do SET NAME=%%~na
REM Gets the last directory name and sets it as a variable
SET ZIPNAME=%NAME% - Originals.zip
SET ZIPNAME2=%NAME% - Photos.zip
if exist ".smaller.txt" del /F ".smaller.txt"
if exist ".larger.txt" del /F ".larger.txt"
if exist "%ZIPNAME%" del /F "%ZIPNAME%" | echo %MYDATE%_%MYTIME%: %COMPUTERNAME% deleted %ZIPNAME%>>%LOG%
if exist "%ZIPNAME2%" del /F "%ZIPNAME2%" | echo %MYDATE%_%MYTIME%: %COMPUTERNAME% deleted %ZIPNAME2%>>%LOG%
REM Deletes old zips if they exists
FOR /F "usebackq delims=;" %%A IN (`dir /b *.jpg *.jpeg *.png *.gif *.bmp`) DO (
IF %%~zA LSS 1048576 (
ECHO %%A >>.smaller.txt
) ELSE (
ECHO %%A >>.larger.txt
)
)
FOR /F "tokens=* delims=" %%x IN (.smaller.txt) DO SET SMALLER=!SMALLER!%%x
FOR /F "tokens=* delims=" %%x IN (.larger.txt) DO SET LARGER=!LARGER!%%x
PAUSE
Here's my end product..
Thanks for all the help!
#ECHO OFF
SETLOCAL EnableDelayedExpansion
FOR /f "tokens=2-4 delims=/ " %%a IN ('date /t') DO (SET mydate=%%c-%%a-%%b)
FOR /f "tokens=1-2 delims=/:" %%a IN ("%TIME%") DO (SET mytime=%%a%%b)
REM My timestamp
SET FOLDER=%~dp1
REM Sets current directory
IF NOT EXIST %SYSTEMDRIVE%\Logs MKDIR %SYSTEMDRIVE%\Logs
SET LOG="%SYSTEMDRIVE%\Logs\.picture_log.txt"
REM Logging file and directory
PUSHD %FOLDER%
REM Changes directory to current
FOR %%A IN ("%CD%") DO SET NAME=%%~NA
REM Gets the last directory name and sets it as a variable
SET ZIP_O=%NAME% - Originals.zip
SET ZIP_R=%NAME% - Photos.zip
REM Zip file names
IF EXIST ".larger.txt" DEL /F ".larger.txt"
IF EXIST ".smaller.txt" DEL /F ".smaller.txt"
REM Delete old temporary files
IF EXIST "%ZIP_O%" DEL /F "%ZIP_O%" | ECHO %MYDATE%_%MYTIME%: %COMPUTERNAME% deleted %ZIP_O%>>%LOG%
IF EXIST "%ZIP_R%" DEL /F "%ZIP_R%" | ECHO %MYDATE%_%MYTIME%: %COMPUTERNAME% deleted %ZIP_R%>>%LOG%
REM Deletes old zips if they exists
FOR /F "usebackq delims=;" %%A IN (`dir /b *.jpg *.jpeg *.png *.gif *.bmp`) DO (
IF %%~zA LSS 1048576 (
ECHO %%A >>.smaller.txt
) ELSE (
ECHO %%A >>.larger.txt
)
)
REM Generate list of files, based off size
FOR /F "tokens=* delims=" %%x IN (.larger.txt) DO SET LARGER=!LARGER!%%x
FOR /F "tokens=* delims=" %%x IN (.smaller.txt) DO SET SMALLER=!SMALLER!%%x
REM Read lists, put contents into variables
"C:\Program Files\7-Zip\7z" a -mx9 -tzip "%ZIP_O%" #.larger.txt -sdel | ECHO %MYDATE%_%MYTIME%: %COMPUTERNAME% compressed %ZIP_O%>>%LOG%
"C:\Program Files\7-Zip\7z" a -mx9 -tzip "%ZIP_R%" #.smaller.txt -sdel | ECHO %MYDATE%_%MYTIME%: %COMPUTERNAME% compressed %ZIP_R%>>%LOG%
REM Compress images in separate .zips
IF EXIST ".larger.txt" DEL /F ".larger.txt"
IF EXIST ".smaller.txt" DEL /F ".smaller.txt"
REM Delete temporary files
The forfiles feature has a #fsize attribute, you can check.
For each file, which is large enough, you perform a 7z.exe a (add to archive).
Related
Can anyone please explain to me how batch scripts work in Windows? I have a folder that contains subfolders, and those contain images. I need a script that automatically deletes images from 7 and up in these subfolders, just to leave a maximum of 6 images in each subfolder, ideally the first 6 alphabetically. I found a few scripts, saved them as .bat, but I have no idea what to do next.
1
#echo off
setlocal
set /a cnt=0
set "keep=6"
for /f "eol=: delims=" %%F in ('dir /b /o-d /a-d *.jpeg') do (
if defined keep (
2>nul set /a "cnt+=1, 1/(keep-cnt)" || set "keep="
) else del "%%F"
)
2
#echo off
for /f "tokens=1* delims=:" %%a in ('dir /b /o-d *.jpeg ^| findstr /N "^"') do (
if %%a gtr 6 del "%%b"
)
3
for /f "skip=7 eol=: delims=" %%F in ('dir /b /o-d /a-d *.jpeg') do #del "%%F"
4
#echo off
setlocal enableextensions disabledelayedexpansion
rem How many elements to keep
set "keep=6"
rem Retrieve folder from batch arguments
set "folder=%~1"
rem If no folder indicated, use current active directory
if not defined folder for %%a in (.) do set "folder=%%~fa"
rem Ensure we are working in the correct folder
pushd "%folder%" && (
rem For each element in the folder, skipping the first n
for /f "skip=%keep% delims=" %%a in (' dir /b /on ') do (
rem If it is a folder, use rmdir, else use del
if exist "%%a\" ( echo rmdir /s /q "%%a" ) else ( echo del "%%a" )
)
rem Work done. Return to previous active directory
popd
) || (
rem Folder change failed
echo Target folder does no exist
)
I finally found a script that works the way I need it to
for /f %%a in ('dir /b /ad') do (
for /f "skip=6" %%b in ('dir /b %%a /on') do (
del %%a\%%b
)
)
In my hard disk I have the following structure:
ROOTFOLDER
├───FOLDER1
│ └───TMPFOLDER
│ ├───FOLDERTODELETE1
│ ├───FOLDERTODELETE2
│ └───FOLDERTODELETE3
├───FOLDER2
│ └───TMPFOLDER
│ ├───FOLDERTODELETE4
│ └───FOLDERTODELETE5
└───FOLDER3
└───TMPFOLDER
├───FOLDERTODELETE6
├───FOLDERTODELETE7
└───FOLDERTODELETE8
I need to create a kind of script (I was thinking about a batch file, but any other solution will be appreciated) to delete all folders within each folders with a specific name (in this case TMPFOLDER) and created before today.
Following to your needs the batch script below will do what you need. Remove the echo in front of the rmdir command if it's okay for you. Take care that the script uses the current working directory. Remove /q if you want to be asked for each directory that should be deleted:
#echo off
set "tmpfolder=TMPFOLDER"
for /f "tokens=*" %%D in ('dir /b /a:d "*"') do (
for /f "tokens=*" %%E in ('dir /b /a:d "%%D\*" ^| findstr /l /x %tmpfolder%') do (
echo Found temp folder: "%%D\%%E"
for /f "tokens=*" %%F in ('dir /b /a:d "%%D\%%E\*"') do (
echo rmdir /s /q "%%D\%%E\%%F"
)
)
)
Edit #1:
The above script does not take care of the creation date of the folder that should be removed. You want only folders to be deleted which have a creation date before today. The following script takes care of that. Look here how to get dates of folder and here how to compare dates:
#echo off
setlocal EnableDelayedExpansion
set "tmpfolder=TMPFOLDER"
for /f "tokens=*" %%D in ('dir /b /a:d "*"') do (
for /f "tokens=*" %%E in ('dir /b /a:d "%%D\*" ^| findstr /x /c:"%tmpfolder%"') do (
rem echo Found temp folder: "%%D\%%E"
for /f "tokens=*" %%F in ('dir /b /a:d "%%D\%%E\*"') do (
rem echo Subfolder: "%%F"
set "curdate=!date!"
set "dirdate="
echo GETDATE
call :getdate dirdate "%%D\%%E\%%F"
set "dirdate=!dirdate:~-4!!dirdate:~3,2!!dirdate:~0,2!"
set "curdate=!curdate:~-4!!curdate:~3,2!!curdate:~0,2!"
rem echo dirdate: "!dirdate!"
rem echo curdate: "!curdate!"
rem echo.
if [!dirdate!] LSS [!curdate!] (
echo rmdir /s /q "%%D\%%E\%%F"
)
)
)
)
goto :EOF
:getdate
rem call: getdate date(dstParam) folder(srcParam)
for /f "skip=5 tokens=1 delims= " %%A in ('dir /a:d /o:d /t:c "%~2"') do (
set "%~1=%%A"
goto :EOF
)
Command reference links from ss64.com:
DelayedExpansion
set
for /f
dir
findstr
if
call
goto
rem
Although an answer has already been accepted, I have decided to post this untested idea as an alternative:
#Echo Off
SetLocal EnableDelayedExpansion
For /F "Delims=" %%A In ('WMIC OS Get LocalDateTime') Do For %%B In (%%~nA
) Do Set "TD=%%B" & Set "TD=!TD:~,8!"
For /D /R "ROOTFOLDER" %%A In ("TMPFOLD?R") Do If /I "%%~nxA"=="TMPFOLDER" (
Set "FP=%%~pA" & Set "FP=!FP:\=\\!"
WMIC FSDir Where "Path='!FP!' And FileName='TMPFOLDER'" Get CreationDate^
|FindStr/B "%TD%">Nul||Echo=RD/S/Q "%%A")
Timeout -1
You may need to change ROOTFOLDER and all instances of TMPFOLDER as necessary, remembering to use a ? to replace one of the characters in the first instance of TMPFOLDER.
If the output appears to be correct, remove the last line and Echo= from the line above it.
This is a very specific question, so I've separated it into 3 parts.
Look in all subfolders for a certain file: world.sav, but only 1 level down, i.e.
C:\workingdir\foo\world.sav
C:\workingdir\bar\world.sav
C:\workingdir\baz\world.sav
C:\workingdir\qux\world.sav
is fine, but
C:\workingdir\foo\bar\world.sav
C:\workingdir\world.sav
isn't, etc.
Sort these world.sav files by date modified (newest first).
Display the name of the subfolder each world.sav file is in, in the previously sorted order. i.e. if the above list was date-sorted into
C:\workingdir\qux\world.sav (newest)
C:\workingdir\bar\world.sav
C:\workingdir\foo\world.sav
C:\workingdir\baz\world.sav (oldest)
then the output would be
qux
bar
foo
baz
I've tried numerous methods involving DIR, FORFILES and manipulation of variables, but the 2 main problems I've come across so far are
Both commands mentioned above will arrange by subfolder, then by date, and I can't find a way to avoid it.
Date formatting. It appears to be different for every localization of Windows, and I really want this to be locale-independent.
Also, it must support spaces in folder names.
EDITED version with a wait message:
#echo off
echo Please wait...
cd /d "c:\workingdir"
(for /d %%a in (*) do #robocopy "%%a" "%%a" world.sav /L /nocopy /is /njh /njs /ndl /nc /ns /ts)|(
#cls
for /f "tokens=2*" %%b in ('sort /r') do #for %%z in ("%%~dpc\.") do #echo %%~nz
)
cd /d "%~dp0"
echo.
pause
original version below
This works here:
robocopy is used on each folder in the directory to generate a list (UTCdate time drv:\path\world.sav format) and that is sorted to get most recent at the top of the list, which the second for parses to extract the drv:\path\folder\world.sav and the last for loop prints out just the folder name.
#echo off
cd /d "c:\workingdir"
(for /d %%a in (*) do #robocopy "%%a" "%%a" world.sav /L /nocopy /is /njh /njs /ndl /nc /ns /ts)|for /f "tokens=2*" %%b in ('sort /r') do #for %%z in ("%%~dpc\.") do #echo %%~nz
pause
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET /a count=0
:: remove variables starting $
FOR /F "delims==" %%a In ('set $ 2^>Nul') DO SET "%%a="
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*" '
) DO IF exist "%sourcedir%\%%a\world.sav" CALL :set$ "%%a"
IF %count%==0 ECHO No files found&GOTO :EOF
IF %count%==1 ECHO %$1%&GOTO :EOF
:sortol
SET /a start=1
SET /a swap=0
:sortil
CALL :compdt
IF %start% neq %count% GOTO sortil
IF %swap% neq 0 GOTO sortol
FOR /l %%a IN (1,1,%count%) DO CALL ECHO %%$%%a%%
GOTO :EOF
:set$
SET /a count+=1
SET "$%count%=%~1"
GOTO :eof
:compdt
CALL SET f1=%%$%start%%%
SET /a START +=1
CALL SET f2=%%$%start%%%
FOR /f %%a IN (
'echo f^|xcopy /L /y /d "%sourcedir%\%f1%\world.sav" "%sourcedir%\%f2%\world.sav"'
) DO SET copies=%%a
IF %copies%==0 GOTO :EOF
SET /a swap +=1
SET /a START -=1
SET "$%start%=%f2%"
SET /a START +=1
SET "$%start%=%f1%"
GOTO :eof
This worked for me. You'd need to set sourcedir to suit your purpose.
Essentially, it builds a list of the next-level-down directory names which contain the target filename in variables $1...$whatever, then sorts the names using a simple bubble-sort which relies on the characteristics of xcopy. XCOPY's /L switch simply lists the files that would be copied; /y tells it to 'go ahead (and not copy)' and /d says 'only later files.ECHOingftellsxcopythat the desired "copy" is a file-copy, so it responds1 file(s) copiedor0...` as its last line, depending on whether the source file was later than the destination.
To reverse the order, simply change the if %copies%==0 to if %copies%==1
An idea :
#echo off
Setlocal EnableDelayedExpansion
set $WorkDir="C:\eh\guh\blugh\fneh\mork\workingdir"
for /f "tokens=*" %%a in ('dir /s/b/a-d %$WorkDir%') do (
for /f "tokens=9 delims=\" %%b in ('echo %%a') do (
if /i "%%b"=="world.sav" call:next "%%~pa" %%~ta
)
)
::Resultat
for /f "tokens=2 delims==" %%r in ('set #') do echo %%r
exit/b
:next
for /f "tokens=7 delims=\" %%c in ('echo %~1') do set $Path=%%c
for /f "tokens=1-3 delims=/" %%c in ('echo %~2') do set #%%e%%d%%c=!$path!
I am new to command prompt scripting and batch files. I have a folder with the following:
file1.pdf
file1.tif
file1_cropped.tif
file1.txt
file2.pdf
file2.tif
file2_cropped.tif
file2.txt...
filen.pdf
filen.tif
filen_cropped.tif
filen.txt
I would like to delete all the tif files that do not have "_cropped" in the filename. I have seen a few solutions for deleting files that have a specified extension, or that match a specific string, but I am trying to combine the two.
Much thanks,
Marc.
for /f "delims=" %%a in ('dir /b /a-d *.tif^|find /v /i "_cropped"') do echo del "%%a"
should suit.
perhaps you'd want
pushd "target directoryname"
for /f "delim...
popd
to specify a directory other than your current to be processed.
The required DEL commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO DEL to DEL to actually delete the files.
From command line, being in target directory:
for /F "eol=: delims=" %a in ('dir /b *.tif ^| find /V "_cropped"') do #del "%a"
Where we have:
FOR /F ["options"] %variable IN ('command') DO command [command-parameters]
In batch file:
for /F "eol=: delims=" %%a in ('dir /b *.tif ^| find /V "_cropped"') do #del "%%a"
A sample where we use a more interactive approach with confirmation:
Use typically as:
the_bat_file.bat exclude_these tif
Where option one is string in file names to exclude and two is file extension.
#echo off
set pat=_cropped
set ext=tif
IF "%1"=="--help" (
echo Usage %0 [exclude] [extension]
echo Default exclude : %pat%
echo Default extension: %ext%
goto end
)
GOTO part1
:confirm
SET /P CONF=Continue y/N?
IF /I "%CONF%" NEQ "Y" GOTO end
goto %con%
:part1
setlocal
IF NOT "%1"=="" set pat=%1
IF NOT "%2"=="" set ext=%2
echo Pattern : %pat%
echo Extension: %ext%
echo.
set con=part2
goto confirm
:part2
echo.
echo Files to delete:
echo.
for /F "eol=: delims=" %%a in ('dir /b "*.%ext%" ^| find /V "%pat%"') do echo "%%a"
echo.
set con=part3
goto confirm
:part3
for /F "eol=: delims=" %%a in ('dir /b "*.%ext%" ^| find /V "%pat%"') do DEL "%%a"
:end
endlocal
I can use this to loop over files:
for %%a in ("%directory%\*.%extension%") do (
echo FILE: %%~fa
)
goto :eof
What if I also rename the files, like this (:rename is a subroutine that renames the files):
for %%a in ("%directory%\*.%extension%") do (
echo FILE: %%~fa
call :rename "%%~fa"
)
goto :eof
In that case, some of the files are renamed (and echoed) two or even three times. I think it's because after they are renamed, in some cases they are regarded as new files that also need to be looped through. However, this does not happen with all the renamed files.
How can I overcome this? I want every file to be renamed only once.
Solution:
:: remove quotes:
:: http://www.dostips.com/?t=Snippets.TrimQuotes
for /f "useback tokens=*" %%a in ('%extension%') do set extension=%%~a
for /f "useback tokens=*" %%a in ('%directory%') do set directory=%%~a
for /f "delims=" %%a in ('dir /b /a-d "%directory%\*.%extension%" ^| sort /r') do (
echo FILE: %directory%\%%a
call :renamingSubroutine "%directory%\%%a"
)
goto :eof
OR:
:: remove quotes:
:: http://www.dostips.com/?t=Snippets.TrimQuotes
for /f "useback tokens=*" %%a in ('%extension%') do set extension=%%~a
for /f "useback tokens=*" %%a in ('%directory%') do set directory=%%~a
for /f "delims=" %%a in ('dir /b /a-d /s /on "%directory%\*.%extension%"') do (
echo FILE: %%~fa
call :renamingSubroutine "%%~fa"
)
goto :eof
try this:
for /f "delims=" %%a in ('dir /b /a-d /s "%directory%\*.%extension%"^|sort /r') do (
echo FILE: %%~fa
call :rename "%%~fa"
)
goto :eof
BTW you shouldn't give batch functions the names of cmd commands (rename).