File batch per eliminare file più vecchi di N giorni

Sto cercando un modo per eliminare tutti i file più vecchi di 7 giorni in un file batch. Ho cercato sul Web e ho trovato alcuni esempi con centinaia di righe di codice e altre che richiedevano l’installazione di utilità di riga di comando aggiuntive per eseguire l’operazione.

Cose simili possono essere fatte in BASH in un paio di linee di codice. Sembra che qualcosa per lo meno remotamente facile potrebbe essere fatto per i file batch in Windows. Sto cercando una soluzione che funzioni in un prompt dei comandi standard di Windows, senza alcuna utilità aggiuntiva. Si prega di no PowerShell o Cygwin neanche.

Godere:

forfiles -p "C:\what\ever" -s -m *.* -d  -c "cmd /c del @path" 

Vedi la documentazione di forfile per maggiori dettagli.

Per ulteriori gadget, fare riferimento a An AZ Index della riga di comando di Windows XP .

Se non hai forfiles installato sul tuo computer, copialo da qualsiasi Windows Server 2003 sul tuo computer Windows XP in %WinDir%\system32\ . Ciò è ansible poiché l’EXE è completamente compatibile tra Windows Server 2003 e Windows XP.

Le versioni successive di Windows e Windows Server sono installate per impostazione predefinita.

Per Windows 7:

La syntax è leggermente cambiata. Pertanto il comando aggiornato è:

 forfiles /p "C:\what\ever" /s /m *.* /D - /C "cmd /c del @path" 

Esegui i seguenti comandi :

 ROBOCOPY C:\source C:\destination /mov /minage:7 del C:\destination /q 

Sposta tutti i file (usando / mov, che sposta i file e poi li cancella in opposizione a / move che sposta interi filtri che vengono poi cancellati) tramite robocopy in un’altra posizione, e poi esegui un comando di cancellazione su quel percorso e sei tutto bene.

Inoltre se hai una directory con molti dati in essa puoi usare /mir switch

Ok, mi annoiavo un po ‘e mi è venuto in mente questo, che contiene la mia versione di sostituzione di epoca di un povero Linux limitata per l’uso quotidiano (nessuna ritenzione di tempo):

7daysclean.cmd

 @echo off setlocal ENABLEDELAYEDEXPANSION set day=86400 set /a year=day*365 set /a strip=day*7 set dSource=C:\temp call :epoch %date% set /a slice=epoch-strip for /f "delims=" %%f in ('dir /adhs /b /s %dSource%') do ( call :epoch %%~tf if !epoch! LEQ %slice% (echo DELETE %%f ^(%%~tf^)) ELSE echo keep %%f ^(%%~tf^) ) exit /b 0 rem Args[1]: Year-Month-Day :epoch setlocal ENABLEDELAYEDEXPANSION for /f "tokens=1,2,3 delims=-" %%d in ('echo %1') do set Years=%%d& set Months=%%e& set Days=%%f if "!Months:~0,1!"=="0" set Months=!Months:~1,1! if "!Days:~0,1!"=="0" set Days=!Days:~1,1! set /a Days=Days*day set /a _months=0 set i=1&& for %%m in (31 28 31 30 31 30 31 31 30 31 30 31) do if !i! LSS !Months! (set /a _months=!_months! + %%m*day&& set /a i+=1) set /a Months=!_months! set /a Years=(Years-1970)*year set /a Epoch=Years+Months+Days endlocal& set Epoch=%Epoch% exit /b 0 

USO

set /a strip=day*7 : Change 7 per il numero di giorni da mantenere.

set dSource=C:\temp : questa è la directory iniziale per verificare la presenza di file.

GLI APPUNTI

Questo è un codice non distruttivo, mostrerà cosa sarebbe successo.

Modificare :

 if !epoch! LEQ %slice% (echo DELETE %%f ^(%%~tf^)) ELSE echo keep %%f ^(%%~tf^) 

a qualcosa di simile:

 if !epoch! LEQ %slice% del /f %%f 

quindi i file vengono effettivamente eliminati

Febbraio : è codificato a 28 giorni. Bissextile anni è un inferno da aggiungere, davvero. se qualcuno ha un’idea che non aggiungerebbe 10 righe di codice, vai avanti e post, quindi aggiungilo al mio codice.

epoca : non ho preso tempo in considerazione, in quanto è necessario eliminare i file più vecchi di una certa data, prendendo ore / minuti avrebbe cancellato i file da un giorno che era destinato a mantenere.

LIMITAZIONE

l’epoca dà per scontato che il formato della data breve sia AAAA-MM-GG. Dovrebbe essere adattato per altre impostazioni o una valutazione del tempo di esecuzione (leggere sShortTime, configurazione associata dall’utente, configurare l’ordine dei campi corretto in un filtro e utilizzare il filtro per estrarre i dati corretti dall’argomento).

Ho già detto che odio l’auto-formation di questo editor? rimuove le righe vuote e il copia-incolla è un inferno.

Spero che aiuti.

 forfiles /p "v:" /s /m *.* /d -3 /c "cmd /c del @path" 

Dovresti fare /d -3 (3 giorni prima) Funziona bene per me. Quindi tutti i batch complicati potrebbero essere nel cestino. Anche i file forfiles non supportano i percorsi UNC, quindi crea una connessione di rete a un’unità specifica.

Dai un’occhiata alla mia risposta a una domanda simile :

 REM del_old.bat REM usage: del_old MM-DD-YYY for /f "tokens=*" %%a IN ('xcopy *.* /d:%1 /L /I null') do if exist %%~nxa echo %%~nxa >> FILES_TO_KEEP.TXT for /f "tokens=*" %%a IN ('xcopy *.* /L /I /EXCLUDE:FILES_TO_KEEP.TXT null') do if exist "%%~nxa" del "%%~nxa" 

Questo elimina i file più vecchi di una determinata data. Sono sicuro che può essere modificato per tornare indietro di sette giorni dalla data corrente.

aggiornamento: noto che HerbCSO è migliorato nello script sopra. Raccomando invece di usare la sua versione .

Il mio comando è

 forfiles -p "d:\logs" -s -m*.log -d-15 -c"cmd /c del @PATH\@FILE" 

@PATH – è solo un percorso nel mio caso, quindi ho dovuto usare @PATH\@FILE

anche forfiles /? non funziona anche per me, ma forfiles (senza “?”) ha funzionato bene.

E l’unica domanda che ho: come aggiungere più maschere (ad esempio ” .log | .bak”)?

Tutto questo per forfiles.exe che ho scaricato qui (su win XP)

Ma se stai usando il server Windows forfiles.exe dovrebbe essere già lì ed è diverso dalla versione ftp. Ecco perché dovrei modificare il comando.

Per Windows Server 2003 sto usando questo comando:

 forfiles -p "d:\Backup" -s -m *.log -d -15 -c "cmd /c del @PATH" 

Per Windows Server 2008 R2:

 forfiles /P c:\sql_backups\ /S /M *.sql /D -90 /C "cmd /c del @PATH" 

Questo cancellerà tutti i file .sql più vecchi di 90 giorni.

Copia questo codice e salvalo come DelOldFiles.vbs.

UTILIZZO SOLO IN COMMAND PROMPT: cscript DelOldFiles.vbs 15

15 significa eliminare file precedenti a 15 giorni.

  'copy from here Function DeleteOlderFiles(whichfolder) Dim fso, f, f1, fc, n, ThresholdDate Set fso = CreateObject("Scripting.FileSystemObject") Set f = fso.GetFolder(whichfolder) Set fc = f.Files Set objArgs = WScript.Arguments n = 0 If objArgs.Count=0 Then howmuchdaysinpast = 0 Else howmuchdaysinpast = -objArgs(0) End If ThresholdDate = DateAdd("d", howmuchdaysinpast, Date) For Each f1 in fc If f1.DateLastModified 

Usa file forfile.

Ci sono diverse versioni. I primi usano i parametri di stile unix.

La mia versione (per server 2000 – non rileva spazio dopo gli interruttori) –

 forfiles -p"C:\what\ever" -s -m*.* -d -c"cmd /c del @path" 

Per aggiungere file forfile a XP, scaricare l’exe da ftp://ftp.microsoft.com/ResKit/y2kfix/x86/

e aggiungilo a C: \ WINDOWS \ system32

IMO, JavaScript sta gradualmente diventando uno standard universale di scripting: è probabilmente disponibile in più prodotti rispetto a qualsiasi altro linguaggio di scripting (in Windows, è disponibile utilizzando Windows Scripting Host). Devo ripulire i vecchi file in molte cartelle, quindi ecco una funzione JavaScript per farlo:

 // run from an administrator command prompt (or from task scheduler with full rights): wscript jscript.js // debug with: wscript /d /x jscript.js var fs = WScript.CreateObject("Scripting.FileSystemObject"); clearFolder('C:\\temp\\cleanup'); function clearFolder(folderPath) { // calculate date 3 days ago var dateNow = new Date(); var dateTest = new Date(); dateTest.setDate(dateNow.getDate() - 3); var folder = fs.GetFolder(folderPath); var files = folder.Files; for( var it = new Enumerator(files); !it.atEnd(); it.moveNext() ) { var file = it.item(); if( file.DateLastModified < dateTest) { var filename = file.name; var ext = filename.split('.').pop().toLowerCase(); if (ext != 'exe' && ext != 'dll') { file.Delete(true); } } } var subfolders = new Enumerator(folder.SubFolders); for (; !subfolders.atEnd(); subfolders.moveNext()) { clearFolder(subfolders.item().Path); } } 

Per ogni cartella da cancellare, basta aggiungere un'altra chiamata alla funzione clearFolder (). Questo particolare codice conserva anche i file exe e dll e pulisce anche le sottocartelle.

Che ne dici di questa modifica su 7daysclean.cmd per tenere conto di un anno bisestile?

Può essere fatto in meno di 10 righe di codice!

 set /a Leap=0 if (Month GEQ 2 and ((Years%4 EQL 0 and Years%100 NEQ 0) or Years%400 EQL 0)) set /a Leap=day set /a Months=!_months!+Leap 

Modifica di Mofi:

La condizione sopra fornita da JR restituisce sempre false a causa di una syntax non valida.

E il Month GEQ 2 è anche sbagliato perché aggiungere 86400 secondi per un altro giorno deve essere fatto in un anno bisestile solo per i mesi da marzo a dicembre, ma non per febbraio.

Un codice funzionante per tenere conto del giorno bisestile – solo nell’anno corrente – nel file batch 7daysclean.cmd pubblicato da Jay sarebbe:

 set "LeapDaySecs=0" if %Month% LEQ 2 goto CalcMonths set /a "LeapRule=Years%%4" if %LeapRule% NEQ 0 goto CalcMonths rem The other 2 rules can be ignored up to year 2100. set /A "LeapDaySecs=day" :CalcMonths set /a Months=!_months!+LeapDaySecs 

Per Windows 2012 R2 il seguente potrebbe funzionare:

  forfiles /p "c:\FOLDERpath" /d -30 /c "cmd /c del @path" 

per vedere i file che verranno cancellati, usa questo

  forfiles /p "c:\FOLDERpath" /d -30 /c "cmd /c echo @path @fdate" 

Ci sono molte domande relative a data / ora relative da risolvere con il file batch. Ma l’interprete della riga di comando cmd.exe non ha alcuna funzione per i calcoli di data / ora. Un sacco di buone soluzioni di lavoro utilizzando applicazioni o script aggiuntivi della console sono già stati pubblicati qui, su altre pagine di Stack Overflow e su altri siti web.

Comune per le operazioni basate su data / ora è il requisito per convertire una stringa data / ora in secondi da un determinato giorno. Molto comune è 1970-01-01 00:00:00 UTC. Tuttavia, è ansible utilizzare qualsiasi giorno successivo a seconda dell’intervallo di date richiesto per supportare un’attività specifica.

Jay ha postato 7daysclean.cmd contenente una veloce soluzione “date to seconds” per l’interprete della riga di comando cmd.exe . Ma non tiene conto degli anni bisestili. JR ha pubblicato un add-on per tenere conto del giorno bisestile dell’anno in corso, ma ignorando gli altri anni bisestili dall’anno di riferimento, ovvero dal 1970.

Uso da 20 anni le tabelle statiche (array) create una volta con una piccola funzione C per ottenere rapidamente il numero di giorni compresi i giorni bisestili dal 1970-01-01 nelle funzioni di conversione data / ora nelle mie applicazioni scritte in C / C ++.

Questo metodo di tabella molto veloce può essere utilizzato anche nel codice batch utilizzando il comando FOR . Così ho deciso di codificare la subroutine batch GetSeconds che calcola il numero di secondi dal 1970-01-01 alle 00:00:00 UTC per una stringa data / ora passata a questa routine.

Nota: i secondi di salto non vengono presi in considerazione poiché anche i file system di Windows non supportano i secondi bisestili.

Innanzitutto, le tabelle:

  1. Giorni dal 1970-01-01 00:00:00 UTC per ogni anno inclusi i giorni bisestili.

     1970 - 1979: 0 365 730 1096 1461 1826 2191 2557 2922 3287 1980 - 1989: 3652 4018 4383 4748 5113 5479 5844 6209 6574 6940 1990 - 1999: 7305 7670 8035 8401 8766 9131 9496 9862 10227 10592 2000 - 2009: 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245 2010 - 2019: 14610 14975 15340 15706 16071 16436 16801 17167 17532 17897 2020 - 2029: 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550 2030 - 2039: 21915 22280 22645 23011 23376 23741 24106 24472 24837 25202 2040 - 2049: 25567 25933 26298 26663 27028 27394 27759 28124 28489 28855 2050 - 2059: 29220 29585 29950 30316 30681 31046 31411 31777 32142 32507 2060 - 2069: 32872 33238 33603 33968 34333 34699 35064 35429 35794 36160 2070 - 2079: 36525 36890 37255 37621 37986 38351 38716 39082 39447 39812 2080 - 2089: 40177 40543 40908 41273 41638 42004 42369 42734 43099 43465 2090 - 2099: 43830 44195 44560 44926 45291 45656 46021 46387 46752 47117 2100 - 2106: 47482 47847 48212 48577 48942 49308 49673 

    Il calcolo dei secondi per l’anno dal 2039 al 2106 con epoca che inizia il 1970-01-01 è ansible solo utilizzando una variabile a 32 bit senza segno, cioè unsigned long (o unsigned int) in C / C ++.

    Ma cmd.exe usa per espressioni matematiche una variabile a 32 bit con segno. Pertanto il valore massimo è 2147483647 (0x7FFFFFFF) che è 2038-01-19 03:14:07.

  2. Informazioni anno bisestile (No / Sì) per gli anni dal 1970 al 2106.

     1970 - 1989: NNYNNNYNNNYNNNYNNNYN 1990 - 2009: NNYNNNYNNNYNNNYNNNYN 2010 - 2029: NNYNNNYNNNYNNNYNNNYN 2030 - 2049: NNYNNNYNNNYNNNYNNNYN 2050 - 2069: NNYNNNYNNNYNNNYNNNYN 2070 - 2089: NNYNNNYNNNYNNNYNNNYN 2090 - 2106: NNYNNNYNNNNNNNYNN ^ year 2100 
  3. Numero di giorni al primo giorno di ogni mese dell’anno in corso.

      Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec Year with 365 days: 0 31 59 90 120 151 181 212 243 273 304 334 Year with 366 days: 0 31 60 91 121 152 182 213 244 274 305 335 

La conversione di una data in un numero di secondi dal 1970-01-01 è abbastanza semplice con queste tabelle.

Attenzione prego!

Il formato delle stringhe di data e ora dipende dalla regione di Windows e dalle impostazioni della lingua. I delimitatori e l’ordine dei token assegnati alle variabili di ambiente Day , Month e Year nel primo ciclo FOR di GetSeconds devono essere adattati al formato data / ora locale, se necessario.

È necessario adattare la stringa di data della variabile di ambiente se il formato di data nella variabile di ambiente DATE è diverso dal formato di data utilizzato dal comando FOR su %%~tF .

Ad esempio quando %DATE% espande a Sun 02/08/2015 mentre %%~tF espande a 02/08/2015 07:38 PM il codice sottostante può essere utilizzato con la modifica della riga 4 a:

 call :GetSeconds "%DATE:~4% %TIME%" 

Questo si traduce in passaggio a subroutine solo il 02/08/2015 – la stringa di data senza le 3 lettere di abbreviazione del giorno della settimana e il carattere di spazio di separazione.

In alternativa, potrebbe essere utilizzato per passare la data corrente nel formato corretto:

 call :GetSeconds "%DATE:~-10% %TIME%" 

Ora gli ultimi 10 caratteri della stringa di data vengono passati alla funzione GetSeconds e quindi non importa se la stringa di date della variabile di ambiente DATE è con o senza giorno della settimana fintanto che il giorno e il mese sono sempre con 2 cifre nell’ordine previsto, cioè nel formato dd/mm/yyyy o dd.mm.yyyy .

Ecco il codice batch con i commenti esplicativi che restituisce solo il file da eliminare e il file da conservare nell’albero delle cartelle C:\Temp , vedere il codice del primo ciclo FOR .

 @echo off setlocal EnableExtensions EnableDelayedExpansion rem Get seconds since 1970-01-01 for current date and time. call :GetSeconds "%DATE% %TIME%" rem Subtract seconds for 7 days from seconds value. set /A "LastWeek=Seconds-7*86400" rem For each file in each subdirectory of C:\Temp get last modification date rem (without seconds -> append second 0) and determine the number of seconds rem since 1970-01-01 for this date/time. The file can be deleted if seconds rem value is lower than the value calculated above. for /F "delims=" %%F in ('dir /ADHS /B /S "C:\Temp"') do ( call :GetSeconds "%%~tF:0" rem if !Seconds! LSS %LastWeek% del /F "%%~fF" if !Seconds! LEQ %LastWeek% ( echo Delete "%%~fF" ) else ( echo Keep "%%~fF" ) ) endlocal goto :EOF rem No validation is made for best performance. So make sure that date rem and hour in string is in a format supported by the code below like rem MM/DD/YYYY hh:mm:ss or M/D/YYYY h:m:s for English US date/time. :GetSeconds rem If there is " AM" or " PM" in time string because of using 12 hour rem time format, remove those 2 strings and in case of " PM" remember rem that 12 hours must be added to the hour depending on hour value. set "DateTime=%~1" set "Add12Hours=0" if "%DateTime: AM=%" NEQ "%DateTime%" ( set "DateTime=%DateTime: AM=%" ) else if "%DateTime: PM=%" NEQ "%DateTime%" ( set "DateTime=%DateTime: PM=%" set "Add12Hours=1" ) rem Get year, month, day, hour, minute and second from first parameter. for /F "tokens=1-6 delims=,-./: " %%A in ("%DateTime%") do ( rem For English US date MM/DD/YYYY or M/D/YYYY set "Day=%%B" & set "Month=%%A" & set "Year=%%C" rem For German date DD.MM.YYYY or English UK date DD/MM/YYYY rem set "Day=%%A" & set "Month=%%B" & set "Year=%%C" set "Hour=%%D" & set "Minute=%%E" & set "Second=%%F" ) rem echo Date/time is: %Year%-%Month%-%Day% %Hour%:%Minute%:%Second% rem Remove leading zeros from the date/time values or calculation could be wrong. if "%Month:~0,1%" EQU "0" ( if "%Month:~1%" NEQ "" set "Month=%Month:~1%" ) if "%Day:~0,1%" EQU "0" ( if "%Day:~1%" NEQ "" set "Day=%Day:~1%" ) if "%Hour:~0,1%" EQU "0" ( if "%Hour:~1%" NEQ "" set "Hour=%Hour:~1%" ) if "%Minute:~0,1%" EQU "0" ( if "%Minute:~1%" NEQ "" set "Minute=%Minute:~1%" ) if "%Second:~0,1%" EQU "0" ( if "%Second:~1%" NEQ "" set "Second=%Second:~1%" ) rem Add 12 hours for time range 01:00:00 PM to 11:59:59 PM, rem but keep the hour as is for 12:00:00 PM to 12:59:59 PM. if "%Add12Hours%" == "1" ( if %Hour% LSS 12 set /A Hour+=12 ) set "DateTime=" set "Add12Hours=" rem Must use 2 arrays as more than 31 tokens are not supported rem by command line interpreter cmd.exe respectively command FOR. set /A "Index1=Year-1979" set /A "Index2=Index1-30" if %Index1% LEQ 30 ( rem Get number of days to year for the years 1980 to 2009. for /F "tokens=%Index1% delims= " %%Y in ("3652 4018 4383 4748 5113 5479 5844 6209 6574 6940 7305 7670 8035 8401 8766 9131 9496 9862 10227 10592 10957 11323 11688 12053 12418 12784 13149 13514 13879 14245") do set "Days=%%Y" for /F "tokens=%Index1% delims= " %%L in ("YNNNYNNNYNNNYNNNYNNNY NNNYNNNYN") do set "LeapYear=%%L" ) else ( rem Get number of days to year for the years 2010 to 2038. for /F "tokens=%Index2% delims= " %%Y in ("14610 14975 15340 15706 16071 16436 16801 17167 17532 17897 18262 18628 18993 19358 19723 20089 20454 20819 21184 21550 21915 22280 22645 23011 23376 23741 24106 24472 24837") do set "Days=%%Y" for /F "tokens=%Index2% delims= " %%L in ("NNYNNNYNNNYNNNYNNNYNN NYNNNYNN") do set "LeapYear=%%L" ) rem Add the days to month in year. if "%LeapYear%" == "N" ( for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M" ) else ( for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M" ) rem Add the complete days in month of year. set /A "Days+=Day-1" rem Calculate the seconds which is easy now. set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second" rem Exit this subroutine goto :EOF 

Per prestazioni ottimali sarebbe meglio rimuovere tutti i commenti, cioè tutte le righe che iniziano con rem dopo 0-4 spazi iniziali.

E gli array possono essere resi anche più piccoli, cioè diminuendo l’intervallo di tempo dal 1980-01-01 alle 00:00:00 al 2038-01-19 03:14:07 come attualmente supportato dal codice batch sopra ad esempio al 2015-01 Da -01 a 2019-12-31 come utilizza il seguente codice che elimina effettivamente i file più vecchi di 7 giorni nella struttura di cartelle C:\Temp .

Inoltre il codice di seguito è ottimizzato per il formato orario di 24 ore.

 @echo off setlocal EnableDelayedExpansion call :GetSeconds "%DATE:~-10% %TIME%" set /A "LastWeek=Seconds-7*86400" for /F "delims=" %%F in ('dir /ADHS /B /S "C:\Temp"') do ( call :GetSeconds "%%~tF:0" if !Seconds! LSS %LastWeek% del /F "%%~fF" ) endlocal goto :EOF :GetSeconds for /F "tokens=1-6 delims=,-./: " %%A in ("%~1") do ( set "Day=%%B" & set "Month=%%A" & set "Year=%%C" set "Hour=%%D" & set "Minute=%%E" & set "Second=%%F" ) if "%Month:~0,1%" EQU "0" ( if "%Month:~1%" NEQ "" set "Month=%Month:~1%" ) if "%Day:~0,1%" EQU "0" ( if "%Day:~1%" NEQ "" set "Day=%Day:~1%" ) if "%Hour:~0,1%" EQU "0" ( if "%Hour:~1%" NEQ "" set "Hour=%Hour:~1%" ) if "%Minute:~0,1%" EQU "0" ( if "%Minute:~1%" NEQ "" set "Minute=%Minute:~1%" ) if "%Second:~0,1%" EQU "0" ( if "%Second:~1%" NEQ "" set "Second=%Second:~1%" ) set /A "Index=Year-2014" for /F "tokens=%Index% delims= " %%Y in ("16436 16801 17167 17532 17897") do set "Days=%%Y" for /F "tokens=%Index% delims= " %%L in ("NYNNN") do set "LeapYear=%%L" if "%LeapYear%" == "N" ( for /F "tokens=%Month% delims= " %%M in ("0 31 59 90 120 151 181 212 243 273 304 334") do set /A "Days+=%%M" ) else ( for /F "tokens=%Month% delims= " %%M in ("0 31 60 91 121 152 182 213 244 274 305 335") do set /A "Days+=%%M" ) set /A "Days+=Day-1" set /A "Seconds=Days*86400+Hour*3600+Minute*60+Second" goto :EOF 

Per ulteriori informazioni sui formati di data e ora e sui confronti dei tempi di file su Windows, vedere la mia risposta su Trova se il file è più vecchio di 4 ore in un file batch con molte informazioni aggiuntive sui tempi dei file.

Potrei aggiungere un modesto contributo a questo thread già prezioso. Sto scoprendo che altre soluzioni potrebbero sbarazzarsi del testo dell’errore attuale ma ignorano il% ERRORLEVEL% che segnala un errore nella mia applicazione. E desidero legittimamente% ERRORLEVEL% finché non si tratta dell’errore “Nessun file trovato”.

Qualche esempio:

Debug ed eliminazione dell’errore in particolare:

 forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 | findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&ECHO found error||echo found success 

Utilizzo di un oneliner per restituire il successo o il fallimento di ERRORLEVEL:

 forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 | findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&EXIT /B 1||EXIT /B 0 

Utilizzando un oneliner per mantenere ERRORLEVEL a zero per il successo nel contesto di un file batch nel mezzo di altro codice (ver> nul reimposta il ERRORLEVEL):

 forfiles /p "[file path...]\IDOC_ARCHIVE" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 | findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&ECHO found error||ver > nul 

Per un passaggio del processo CmdExec di SQL Server Agent sono arrivato a quanto segue. Non so se si tratta di un bug, ma il CmdExec all’interno del passo riconosce solo la prima riga di codice:

 cmd /e:on /c "forfiles /p "C:\SQLADMIN\MAINTREPORTS\SQL2" /s /m *.txt /d -1 /c "cmd /c del @path" 2>&1 | findstr /V /O /C:"ERROR: No files found with the specified search criteria."2>&1 | findstr ERROR&&EXIT 1||EXIT 0"&exit %errorlevel% 

Se si dispone del kit di risorse XP, è ansible utilizzare robocopy per spostare tutte le vecchie directory in un’unica directory, quindi utilizzare rmdir per eliminare solo quella:

 mkdir c:\temp\OldDirectoriesGoHere robocopy c:\logs\SoManyDirectoriesToDelete\ c:\temp\OldDirectoriesGoHere\ /move /minage:7 rmdir /s /qc:\temp\OldDirectoriesGoHere 

Penso che la risposta di e.James sia buona poiché funziona con versioni non modificate di Windows già in Windows 2000 SP4 (e forse prima), ma ha richiesto la scrittura su un file esterno. Ecco una versione modificata che non crea un file di testo esterno mantenendo la compatibilità:

 REM del_old.cmd REM usage: del_old MM-DD-YYYY setlocal enabledelayedexpansion for /f "tokens=*" %%a IN ('xcopy *.* /d:%1 /L /I null') do @if exist "%%~nxa" set "excludefiles=!excludefiles!;;%%~nxa;;" for /f "tokens=*" %%a IN ('dir /b') do @(@echo "%excludefiles%"|FINDSTR /C:";;%%a;;">nul || if exist "%%~nxa" DEL /F /Q "%%a">nul 2>&1) 

Per essere fedele alla domanda originale, qui è in uno script che fa TUTTA la matematica per te se la chiami con il numero di giorni come parametro:

 REM del_old_compute.cmd REM usage: del_old_compute N setlocal enabledelayedexpansion set /a days=%1&set cur_y=%DATE:~10,4%&set cur_m=%DATE:~4,2%&set cur_d=%DATE:~7,2% for /f "tokens=1 delims==" %%a in ('set cur_') do if "!%%a:~0,1!"=="0" set /a %%a=!%%a:~1,1!+0 set mo_2=28&set /a leapyear=cur_y*10/4 if %leapyear:~-1% equ 0 set mo_2=29 set mo_1=31&set mo_3=31&set mo_4=30&set mo_5=31 set mo_6=30&set mo_7=31&set mo_8=31&set mo_9=30 set mo_10=31&set mo_11=30&set mo_12=31 set /a past_y=(days/365) set /a monthdays=days-((past_y*365)+((past_y/4)*1))&&set /a past_y=cur_y-past_y&set months=0 :setmonth set /a minusmonth=(cur_m-1)-months if %minusmonth% leq 0 set /a minusmonth+=12 set /a checkdays=(mo_%minusmonth%) if %monthdays% geq %checkdays% set /a months+=1&set /a monthdays-=checkdays&goto :setmonth set /a past_m=cur_m-months set /a lastmonth=cur_m-1 if %lastmonth% leq 0 set /a lastmonth+=12 set /a lastmonth=mo_%lastmonth% set /a past_d=cur_d-monthdays&set adddays=:: if %past_d% leq 0 (set /a past_m-=1&set adddays=) if %past_m% leq 0 (set /a past_m+=12&set /a past_y-=1) set mo_2=28&set /a leapyear=past_y*10/4 if %leapyear:~-1% equ 0 set mo_2=29 %adddays%set /a past_d+=mo_%past_m% set d=%past_m%-%past_d%-%past_y% for /f "tokens=*" %%a IN ('xcopy *.* /d:%d% /L /I null') do @if exist "%%~nxa" set "excludefiles=!excludefiles!;;%%~nxa;;" for /f "tokens=*" %%a IN ('dir /b') do @(@echo "%excludefiles%"|FINDSTR /C:";;%%a;;">nul || if exist "%%~nxa" DEL /F /Q "%%a">nul 2>&1) 

NOTA: il codice sopra riportato tiene conto degli anni bisestili e del numero esatto di giorni di ogni mese. L’unico massimo è il numero totale di giorni che ci sono stati dal 0/0/0 (dopo che restituisce gli anni negativi).

NOTA: la matematica va solo in un modo; non può ottenere correttamente date future da input negativi (ci proverà, ma probabilmente andrà oltre l’ultimo giorno del mese).

Potresti riuscire a tirarlo fuori. Puoi dare un’occhiata a questa domanda , per un esempio più semplice. La complessità arriva quando inizi a confrontare le date. Potrebbe essere facile capire se la data è maggiore o meno, ma ci sono molte situazioni da considerare se è necessario ottenere effettivamente la differenza tra due date.

In altre parole, non provare a inventarlo, a meno che tu non sia davvero in grado di utilizzare gli strumenti di terze parti.

questo non è niente di straordinario, ma ho dovuto fare qualcosa di simile oggi ed eseguirlo come compito programmato ecc.

file batch, DelFilesOlderThanNDays.bat di seguito con esempio di esempio con parametri:

DelFilesOlderThanNDays.bat 7 C: \ dir1 \ dir2 \ dir3 \ logs * .log

 echo off cls Echo( SET keepDD=%1 SET logPath=%2 :: example C:\dir1\dir2\dir3\logs SET logFileExt=%3 SET check=0 IF [%3] EQU [] SET logFileExt=*.log & echo: file extention not specified (default set to "*.log") IF [%2] EQU [] echo: file directory no specified (a required parameter), exiting! & EXIT /B IF [%1] EQU [] echo: number of days not specified? :) echo( echo: in path [ %logPath% ] echo: finding all files like [ %logFileExt% ] echo: older than [ %keepDD% ] days echo( :: :: :: LOG echo: >> c:\trimLogFiles\logBat\log.txt echo: executed on %DATE% %TIME% >> c:\trimLogFiles\logBat\log.txt echo: ---------------------------------------------------------- >> c:\trimLogFiles\logBat\log.txt echo: in path [ %logPath% ] >> c:\trimLogFiles\logBat\log.txt echo: finding all files like [ %logFileExt% ] >> c:\trimLogFiles\logBat\log.txt echo: older than [ %keepDD% ] days >> c:\trimLogFiles\logBat\log.txt echo: ---------------------------------------------------------- >> c:\trimLogFiles\logBat\log.txt :: FORFILES /p %logPath% /s /m %logFileExt% /d -%keepDD% /c "cmd /c echo @path" >> c:\trimLogFiles\logBat\log.txt 2<&1 IF %ERRORLEVEL% EQU 0 ( FORFILES /p %logPath% /s /m %logFileExt% /d -%keepDD% /c "cmd /c echo @path" ) :: :: :: LOG IF %ERRORLEVEL% EQU 0 ( echo: >> c:\trimLogFiles\logBat\log.txt echo: deleting files ... >> c:\trimLogFiles\logBat\log.txt echo: >> c:\trimLogFiles\logBat\log.txt SET check=1 ) :: :: IF %check% EQU 1 ( FORFILES /p %logPath% /s /m %logFileExt% /d -%keepDD% /c "cmd /c del @path" ) :: :: RETURN & LOG :: IF %ERRORLEVEL% EQU 0 echo: deletion successfull! & echo: deletion successfull! >> c:\trimLogFiles\logBat\log.txt echo: ---------------------------------------------------------- >> c:\trimLogFiles\logBat\log.txt 

Expanding on aku’s answer, I see a lot of people asking about UNC paths. Simply mapping the unc path to a drive letter will make forfiles happy. Mapping and unmapping of drives can be done programmatically in a batch file, for example.

 net use Z: /delete net use Z: \\unc\path\to\my\folder forfiles /p Z: /s /m *.gz /D -7 /C "cmd /c del @path" 

This will delete all files with a .gz extension that are older than 7 days. If you want to make sure Z: isn’t mapped to anything else before using it you could do something simple as

 net use Z: \\unc\path\to\my\folder if %errorlevel% equ 0 ( forfiles /p Z: /s /m *.gz /D -7 /C "cmd /c del @path" ) else ( echo "Z: is already in use, please use another drive letter!" ) 

ROBOCOPY works great for me. Originally suggested my Iman. But instead of moving the files/folders to a temporary directory then deleting the contents of the temporary folder, move the files to the trash!!!

This is is a few lines of my backup batch file for example:

 SET FilesToClean1=C:\Users\pauls12\Temp SET FilesToClean2=C:\Users\pauls12\Desktop\1616 - Champlain\Engineering\CAD\Backups SET RecycleBin=C:\$Recycle.Bin\S-1-5-21-1480896384-1411656790-2242726676-748474 robocopy "%FilesToClean1%" "%RecycleBin%" /mov /MINLAD:15 /XA:SH /NC /NDL /NJH /NS /NP /NJS robocopy "%FilesToClean2%" "%RecycleBin%" /mov /MINLAD:30 /XA:SH /NC /NDL /NJH /NS /NP /NJS 

It cleans anything older than 15 days out of my ‘Temp’ folder and 30 days for anything in my AutoCAD backup folder. I use variables because the line can get quite long and I can reuse them for other locations. You just need to find the dos path to your recycle bin associated with your login.

This is on a work computer for me and it works. I understand that some of you may have more restrictive rights but give it a try anyway;) Search Google for explanations on the ROBOCOPY parameters.

Saluti!

Gosh, a lot of answers already. A simple and convenient route I found was to execute ROBOCOP.EXE twice in sequential order from a single Windows command line instruction using the & parameter.

 ROBOCOPY.EXE SOURCE-DIR TARGET-DIR *.* /MOV /MINAGE:30 & ROBOCOPY.EXE SOURCE-DIR TARGET-DIR *.* /MOV /MINAGE:30 /PURGE 

In this example it works by picking all files ( . ) that are older than 30 days old and moving them to the target folder. The second command does the same again with the addition of the PURGE command which means remove files in the target folder that don’t exist in the source folder. So essentially, the first command MOVES files and the second DELETES because they no longer exist in the source folder when the second command is invoked.

Consult ROBOCOPY’s documentation and use the /L switch when testing.

You’re probably not going to find a totally non install solution short of a complicated bat file or windows script. I use delen , drop it in a system directory then use it like the regular del command in any bat file.

This one did it for me. It works with a date and you can substract the wanted amount in years to go back in time:

 @echo off set m=%date:~-7,2% set /A m set dateYear=%date:~-4,4% set /A dateYear -= 2 set DATE_DIR=%date:~-10,2%.%m%.%dateYear% forfiles /p "C:\your\path\here\" /s /m *.* /d -%DATE_DIR% /c "cmd /c del @path /F" pause 

the /F in the cmd /c del @path /F forces the specific file to be deleted in some the cases the file can be read-only.

the dateYear is the year Variable and there you can change the substract to your own needs

My script to delete files older than a specific year :

 @REM _______ GENERATE A CMD TO DELETE FILES OLDER THAN A GIVEN YEAR @REM _______ (given in _olderthanyear variable) @REM _______ (you must LOCALIZE the script depending on the dir cmd console output) @REM _______ (we assume here the following line's format "11/06/2017 15:04 58 389 SpeechToText.zip") @set _targetdir=c:\temp @set _olderthanyear=2017 @set _outfile1="%temp%\deleteoldfiles.1.tmp.txt" @set _outfile2="%temp%\deleteoldfiles.2.tmp.txt" @if not exist "%_targetdir%" (call :process_error 1 DIR_NOT_FOUND "%_targetdir%") & (goto :end) :main @dir /adhs /s /b %_targetdir%\*>%_outfile1% @for /F "tokens=*" %%F in ('type %_outfile1%') do @call :process_file_path "%%F" %_outfile2% @goto :end :end @rem ___ cleanup and exit @if exist %_outfile1% del %_outfile1% @if exist %_outfile2% del %_outfile2% @goto :eof :process_file_path %1 %2 @rem ___ get date info of the %1 file path @dir %1 | find "/" | find ":" > %2 @for /F "tokens=*" %%L in ('type %2') do @call :process_line "%%L" %1 @goto :eof :process_line %1 %2 @rem ___ generate a del command for each file older than %_olderthanyear% @set _var=%1 @rem LOCALIZE HERE (char-offset,string-length) @set _fileyear=%_var:~0,4% @set _fileyear=%_var:~7,4% @set _filepath=%2 @if %_fileyear% LSS %_olderthanyear% echo @REM %_fileyear% @if %_fileyear% LSS %_olderthanyear% echo @del %_filepath% @goto :eof :process_error %1 %2 @echo RC=%1 MSG=%2 %3 @goto :eof