File batch per eliminare file più vecchi di N giorni


678

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

Cose simili possono essere fatte in BASH in solo un paio di righe di codice. Sembra che si possa fare qualcosa di almeno remoto per file batch in Windows. Sto cercando una soluzione che funzioni in un prompt dei comandi di Windows standard, senza utilità aggiuntive. Per favore, neanche PowerShell o Cygwin.


8
Jeff Atwood ha risposto a questo su Serverfault che penso dovrebbe essere documentato qui. serverfault.com/questions/49614/delete-files-older-than-x-days
Dusty

Un nuovo metodo basato in un file bat che utilizzano i comandi interni CMD.EXE solo si è pubblicato qui: stackoverflow.com/questions/9746778/...
Aacini

1
gehrcke.de/timegaps è stato progettato per questo scopo. Permette persino uno schema di cancellazione più sofisticato: oltre a conservare i file degli ultimi 7 giorni, ad esempio consente anche di conservare un file per ciascuna delle ultime 8 settimane, 12, mesi, 2 anni.
Dr. Jan-Philip Gehrcke,

Risposte:


1071

Godere:

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

Vedi la forfilesdocumentazione per maggiori dettagli.

Per altri gadget, fare riferimento a Un indice AZ della riga di comando di Windows XP .

Se non è stato forfilesinstallato sul computer, copiarlo da qualsiasi Windows Server 2003 sul computer Windows XP all'indirizzo %WinDir%\system32\. Ciò è possibile poiché EXE è completamente compatibile tra Windows Server 2003 e Windows XP.

Le versioni successive di Windows e Windows Server lo hanno installato per impostazione predefinita.

Per Windows 7 e versioni successive (incluso Windows 10):

La sintassi è cambiata un po '. Pertanto il comando aggiornato è:

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

12
Dovrebbe essere del @FILE, questioni del caso Inoltre suggerisco di utilizzare / c echo @FILE per i test
Russell Steen,

40
@Russell: @PATH è il percorso completo, incluso il nome. @FILE è solo il nome, quindi se hai a che fare con le sottocartelle, non funzionerà.
gregmac,

86
Notare che se si desidera un file OLDER di 10 giorni, è necessario specificare -d "-10". -ve significa "più vecchio di", + ve significa "più nuovo di". È inoltre possibile specificare il formato DDMMYY o -DDMMYY come parametro per -d.
gregmac,

42
Ho usato questa sintassi su Win Server 2008: forfiles / P "C: \ Mysql_backup" / S / M * .sql / D -30 / C "cmd / c del @PATH"
jman,

9
Questa risposta funziona quando "più vecchio di 7 giorni" è definito come "modificato più di 7 giorni fa" anziché "creato più di 7 giorni fa". Come si può ottenere quest'ultimo?
TimS,

76

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 li elimina invece di / move che sposta interi file che vengono poi eliminati) tramite robocopy in un'altra posizione, quindi esegui un comando di eliminazione su quel percorso e sei tutto bene.

Inoltre, se hai una directory con molti dati, puoi usare /mirswitch


5
Per la maggior parte, questa è una risposta abbastanza poco pratica. Se ho una directory con molti dati, non funzionerà bene. Vorrei andare con una delle risposte che lo fa "sul posto"
adamb0mb

5
@ adamb0mb questo non è in alcun modo impraticabile - se "destinazione" si trova sullo stesso filesystem di "origine" , l'operazione di spostamento è piuttosto leggera. Poiché robocopy è veramente robusto, funzionerà di fatto per qualsiasi dimensione di directory, oscurerà i nomi dei file, sostanzialmente lunghezze dei percorsi arbitrarie e includerà le directory se ne hai bisogno, qualcosa che sicuramente non si può dire su molte altre utility di Windows. Vorrei usare rd /s /q c:\destinationinvece del delcomando o anche usare un'altra robocopy /mir c:\emptydir c:\destinationcorsa per svuotare la directory se ti aspetti problemi con i nomi dei file.
syneticon-dj,

12
Inoltre, robocopy supporta percorsi UNC, cosa che forfilesdalla risposta accettata non farà.
syneticon-dj,

3
I miei pensieri erano più in linea: "I miei file sono già dove li voglio. Non voglio spostarli." "L'eliminazione dei file è logicamente ciò che stai facendo, quindi fallo. Non sovraccaricare Robocopy per farlo"
adamb0mb

3
Consiglio questo one-liner per visualizzare tutti i file in C:\testmeno di 7 giorni. Per eliminare i file, modificare echoin del:forfiles /p "C:\test" /m "*.*" /c "cmd /c echo @file" /D -7
PowerUser

25

Ok era un po 'annoiato e ne è uscito questo, che contiene la mia versione della sostituzione di epoca Linux di un uomo povero, limitata per l'uso quotidiano (nessuna conservazione del 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 /a-d-h-s /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: Modifica 7 per il numero di giorni da conservare.

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

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 come:

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

quindi i file vengono effettivamente eliminati

Febbraio : è programmato per 28 giorni. Gli anni bisessili sono un inferno da aggiungere, davvero. se qualcuno ha un'idea che non aggiungerebbe 10 righe di codice, vai avanti e pubblica quindi lo aggiungo al mio codice.

epoca : non ho preso in considerazione il tempo, poiché la necessità è quella di eliminare i file più vecchi di una certa data, impiegando ore / minuti si sarebbero eliminati i file da un giorno che doveva essere conservato.

LIMITAZIONE

l'epoca dà per scontato che il formato della data breve sia AAAA-MM-GG. Dovrebbe essere adattato per altre impostazioni o per una valutazione di runtime (leggi sShortTime, configurazione associata all'utente, configura l'ordine dei campi corretto in un filtro e usa il filtro per estrarre i dati corretti dall'argomento).

Ho già detto che odio la formulazione automatica di questo editore? rimuove le righe vuote e il copia-incolla è un inferno.

Spero che questo possa essere d'aiuto.


4
+1 per il codice non distruttivo, cercherò di tenerlo presente quando fornisco io stesso esempi di codice.
Haugholt,

5
Molto tardi e totalmente estraneo, ma 7daysclean.cmdsuona come un nome fantastico per una band Synth-Punk.
Flonk,

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

Dovresti farlo /d -3(3 giorni prima) Questo funziona bene per me. Quindi tutti i lotti complicati potrebbero essere nel cestino. Inoltre forfiles, non supporta percorsi UNC, quindi effettua una connessione di rete a un'unità specifica.


3
Stesso errore delle altre risposte (inclusa quella accettata). Da dove viene questa strana abitudine di specificare *.*? Il carattere jolly *.*non corrisponde a tutti i file in Windows. Corrisponde solo ai file con .nei loro nomi. L'OP non ha mai detto nulla riguardo alla richiesta .nel nome del file. Il parametro corretto è /M *, ma questo è comunque il valore predefinito. Non ce n'è affatto bisogno /M.
Il

@AnT: Sei sicuro? Penso che *.*si comporti esattamente come *in Windows. In effetti, l'ho appena provato sul mio computer, e in dir *.*effetti elencato test file, un file senza estensione.
Andreas Rejbrand,

1
@Andreas Rejbrand: lo trovo anche sorprendente, ma il trattamento di *.*è incoerente tra, diciamo, dire l' -mopzione di forfiles. La -m *.*maschera salterà infatti i nomi dei file senza estensione, come ho affermato nel mio commento sopra (provalo tu stesso). La parte divertente qui è che la documentazione MS afferma esplicitamente che -m *.*è l'impostazione predefinita. Tuttavia, se lo provi nella vita reale, vedrai che l'impostazione predefinita è in realtà -m *- tutti i file sono iterati.
Un

1
Questa pagina della documentazione MS - technet.microsoft.com/en-us/library/cc753551(v=ws.11).aspx - contiene un gran numero di errori (ad esempio negli esempi) perché l'autore del documento ha erroneamente ritenuto che la *.*maschera fosse applicata a tutti i file. La mia domanda retorica su "questa strana abitudine" è stata in effetti non richiesta, poiché trattare *.*e *come equivalente è una convenzione di Windows di lunga data. Tuttavia, l' /mopzione forfilesper violare tale convenzione per qualche motivo.
An

1
Sfondo sui 5 caratteri jolly in Windows: blogs.msdn.microsoft.com/jeremykuhne/2017/06/04/…
MSalters

18

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"

Ciò 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. Consiglio invece di usare la sua versione .


12

Il mio comando è

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

@PATH - è solo il 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 ciò che riguarda forfiles.exe che ho scaricato qui (su Windows 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"

9

Molto spesso ci sono domande relative relative a data / ora da risolvere con file batch. L'interprete della riga di comando cmd.exe non ha alcuna funzione per i calcoli di data / ora. Molte buone soluzioni funzionanti che utilizzano applicazioni o script di console aggiuntivi sono già state pubblicate qui, su altre pagine di Stack Overflow e su altri siti Web.

Comune per le operazioni basate su data / ora è il requisito di convertire una stringa di data / ora in secondi da un determinato giorno. Molto comune è 1970-01-01 00:00:00 UTC. Ma qualsiasi giorno successivo potrebbe essere utilizzato anche in base all'intervallo di date richiesto per supportare un'attività specifica.

Jay ha pubblicato 7daysclean.cmd contenente una soluzione rapida "data in secondi" per l'interprete della riga di comando cmd.exe . Ma non ci vogliono anni bisestili corretti in considerazione. JR ha pubblicato un componente aggiuntivo per tenere conto del giorno bisestile nell'anno in corso, ma ignorando gli altri anni bisestili dall'anno base, ovvero dal 1970.

Uso da 20 anni tabelle statiche (array) create una volta con una piccola funzione C per ottenere rapidamente il numero di giorni inclusi 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 usando il comando FOR . Così ho deciso di codificare la subroutine batch GetSecondsche calcola il numero di secondi dal 1970-01-01 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 di salto.

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 a partire dal 1970-01-01 è possibile solo utilizzando una variabile a 32 bit senza segno, ovvero unsigned long (o unsigned int) in C / C ++.

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

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

    1970 - 1989: N N Y N N N Y N N N Y N N N Y N N N Y N
    1990 - 2009: N N Y N N N Y N N N Y N N N Y N N N Y N
    2010 - 2029: N N Y N N N Y N N N Y N N N Y N N N Y N
    2030 - 2049: N N Y N N N Y N N N Y N N N Y N N N Y N
    2050 - 2069: N N Y N N N Y N N N Y N N N Y N N N Y N
    2070 - 2089: N N Y N N N Y N N N Y N N N Y N N N Y N
    2090 - 2106: N N Y N N N Y N N N N N N N Y N N
                                     ^ year 2100
    
  3. Numero di giorni al primo giorno di ogni mese nell'anno corrente.

                       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 numero di secondi dal 1970-01-01 è abbastanza facile usando queste tabelle.

Attenzione prego!

Il formato delle stringhe di data e ora dipende dall'area di Windows e dalle impostazioni della lingua. I delimitatori e l'ordine dei token assegnati alle variabili di ambiente Day, Monthe Yearnel primo ciclo FOR di, GetSecondsdevono essere adattati al formato data / ora locale, se necessario.

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

Ad esempio, quando si %DATE%espande a Sun 02/08/2015mentre si %%~tFespande al 02/08/2015 07:38 PMseguente codice può essere utilizzato con la modifica della riga 4 per:

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

Ciò comporta il passaggio alla subroutine 02/08/2015: la stringa della data senza le 3 lettere dell'abbreviazione del giorno della settimana e il carattere di spazio di separazione.

In alternativa, è possibile utilizzare la seguente per passare la data corrente nel formato corretto:

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

Ora gli ultimi 10 caratteri dalla stringa di data vengono passati alla funzione GetSecondse quindi non importa se la stringa di data della variabile di ambiente DATE è con o senza giorno della settimana, purché il giorno e il mese siano sempre con 2 cifre nell'ordine previsto, cioè nel formato dd/mm/yyyy o dd.mm.yyyy.

Ecco il codice batch con spiegazione dei commenti che mostra semplicemente quale file eliminare e quale file conservare nell'albero delle C:\Tempcartelle, 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 /A-D-H-S /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 ("Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N") 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 ("N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N N Y N N") 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 le matrici possono essere ridotte anche, ovvero diminuendo l'intervallo di tempo dal 1980-01-01 00:00:00 al 2038-01-19 03:14:07 come attualmente supportato dal codice batch sopra, ad esempio al 2015-01 -01 al 2019-12-31 come usa il codice seguente che elimina davvero i file più vecchi di 7 giorni nell'albero delle C:\Tempcartelle.

Inoltre il codice batch 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 /A-D-H-S /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 ("N Y N N N") 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 confronti dei tempi dei file su Windows, vedere la mia risposta su Scopri se il file è più vecchio di 4 ore nel file batch con molte ulteriori informazioni sui tempi dei file.


9

Copia questo codice e salvalo come DelOldFiles.vbs.

UTILIZZO IN CMD: cscript //nologo DelOldFiles.vbs 15

15 significa eliminare i file più vecchi di 15 giorni in passato.

  '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<ThresholdDate Then
        Wscript.StdOut.WriteLine f1
        f1.Delete
        n = n + 1    
     End If
       Next
       Wscript.StdOut.WriteLine "Deleted " & n & " file(s)."
    End Function

    If Not WScript.FullName = WScript.Path & "\cscript.exe" Then
      WScript.Echo "USAGE ONLY IN COMMAND PROMPT: cscript DelOldFiles.vbs 15" & vbCrLf & "15 means to delete files older than 15 days in past."
      WScript.Quit 0   
    End If

    DeleteOlderFiles(".")
 'to here

8

Per Windows Server 2008 R2:

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

Ciò eliminerà tutti i file .sql più vecchi di 90 giorni.


7

Usa i file.

Esistono diverse versioni. I primi usano parametri di stile unix.

La mia versione (per server 2000 - notare spazio dopo gli switch) -

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

Per aggiungere forfile a XP, scarica l'exe da ftp://ftp.microsoft.com/ResKit/y2kfix/x86/

e aggiungilo a C: \ WINDOWS \ system32


11
@Kibbee non è la stessa risposta, la sintassi è diversa. Questo è stato un geniale tentativo di aiutare. Conoscendo pochissimo della riga di comando di Windows, ho passato ore di frustrazione a farlo funzionare. Le informazioni chiave per me sono state il fatto che esistono versioni diverse (con sintassi diversa) e che avevo bisogno di rimuovere gli spazi. Nessuna di queste cose era inclusa nella risposta originale. (Avrei commentato la risposta ma non ho i privilegi
Aidan Ewen,

Stesso errore delle altre risposte (inclusa quella accettata). Il carattere jolly *.*in forfilesnon corrisponde a tutti i file. Corrisponde solo ai file con .nei loro nomi (cioè file con estensioni). L'OP non ha mai detto nulla riguardo alla richiesta .nel nome del file. Il parametro corretto è /M *, ma questo è comunque il valore predefinito. Non ce n'è affatto bisogno /M.
An

7

Per Windows 2012 R2 dovrebbe funzionare quanto segue:

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

per vedere i file che verranno eliminati usa questo

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

Funziona anche con Windows Server 2008 e versioni successive e Windows 7.
kwrl,

6

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 cancellare ogni cartella, basta aggiungere un'altra chiamata alla funzione clearFolder (). Questo particolare codice conserva anche i file exe e dll e pulisce anche le sottocartelle.


6

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 codifica!

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 viene sempre valutata come falsa a causa di una sintassi non valida.

Ed 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 in corso - 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

5

Potrei aggiungere un modesto contributo a questo filo già prezioso. Sto scoprendo che altre soluzioni potrebbero sbarazzarsi del testo dell'errore effettivo ma stanno ignorando% ERRORLEVEL% che segnala un errore nella mia applicazione. E voglio legittimamente% ERRORLEVEL% purché non sia l'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

Utilizzo di un oneliner per mantenere ERRORLEVEL a zero in caso di successo nel contesto di un file batch nel mezzo di altro codice (ver> nul reimposta 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 al seguente punto. Non so se si tratta di un bug, ma CmdExec all'interno del passaggio 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%

5

Accidenti, già molte risposte. Un percorso semplice e conveniente che ho trovato è stato quello di eseguire ROBOCOPY.EXE due volte in ordine sequenziale da una singola istruzione della riga di comando di Windows usando il parametro & .

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

In questo esempio funziona selezionando tutti i file ( . ) Più vecchi di 30 giorni e spostandoli nella cartella di destinazione. Il secondo comando fa di nuovo lo stesso con l'aggiunta del comando PURGE che significa rimuovere i file nella cartella di destinazione che non esistono nella cartella di origine. Quindi, essenzialmente, il primo comando SPOSTA i file e il secondo ELIMINA perché non esistono più nella cartella di origine quando viene richiamato il secondo comando.

Consultare la documentazione di ROBOCOPY e utilizzare l'opzione / L durante il test.


4

Se si dispone del kit di risorse XP, è possibile utilizzare robocopy per spostare tutte le vecchie directory in una singola directory, quindi utilizzare rmdir per eliminare solo quello:

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

4

Penso che la risposta di e.James sia buona poiché funziona con versioni non modificate di Windows già da 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 fedeli alla domanda originale, eccolo 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, nonché del numero esatto di giorni in ogni mese. L'unico massimo è il numero totale di giorni trascorsi dallo 0/0/0 (dopo che restituisce anni negativi).

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


3

Potresti riuscire a farlo. Puoi dare un'occhiata a questa domanda , per un esempio più semplice. La complessità arriva quando inizi a confrontare le date. Può essere facile dire 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 tentare di inventare questo, a meno che tu non sia davvero in grado di utilizzare gli strumenti di terze parti.


3

questo non è niente di straordinario, ma oggi dovevo fare qualcosa del genere ed eseguirlo come attività pianificata ecc.

file batch, DelFilesOlderThanNDays.bat di seguito con esempio di esecuzione 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

3

Espandendo la risposta di Aku, vedo molte persone che chiedono informazioni sui percorsi UNC. La semplice mappatura del percorso unc su una lettera di unità renderà felici i file. La mappatura e l'annullamento della mappatura delle unità possono essere eseguite programmaticamente in un file batch, ad esempio.

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"

Ciò eliminerà tutti i file con estensione .gz che sono più vecchi di 7 giorni. Se vuoi assicurarti che Z: non sia mappato su nient'altro prima di usarlo, potresti fare qualcosa di semplice

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!"
)

3

La ROBOCOPIA funziona benissimo per me. Inizialmente suggerito il mio Iman. Ma invece di spostare i file / le cartelle in una directory temporanea, quindi eliminare il contenuto della cartella temporanea, spostare i file nel cestino !!!

Queste sono alcune righe del mio file batch di backup, ad esempio:

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

Elimina tutto ciò che è più vecchio di 15 giorni dalla mia cartella "Temp" e 30 giorni per qualsiasi cosa nella mia cartella di backup di AutoCAD. Uso le variabili perché la linea può diventare piuttosto lunga e posso riutilizzarle per altre posizioni. Devi solo trovare il percorso del DOS nel cestino associato al tuo login.

Questo è su un computer di lavoro per me e funziona. Comprendo che alcuni di voi potrebbero avere diritti più restrittivi, ma provatelo comunque;) Cerca su Google spiegazioni sui parametri di ROBOCOPY.

Saluti!


1
L'attuale seconda risposta più votata sposa anche RoboCopy. Certo, usi opzioni leggermente diverse, ma è vicino alla risposta esistente.
Jonathan Leffler,

2
Questo post ha un nuovo contenuto: lo spostamento dei file nel cestino. Questo non è stato ancora proposto con Robocopy e risponde completamente al post originale utilizzando un comando a riga singola incorporato. Funziona meglio della combinazione dei comandi 'DEL' e 'RMDIR' perché i file possono essere ripristinati dal cestino. Ehi, sono ancora nuovo qui - dammi una pausa;)
Shawn Pauliszyn,

2

Il mio script per eliminare i file più vecchi di un anno specifico:

@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 /a-d-h-s /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

1

Questo è stato per me. Funziona con una data e puoi sottrarre la quantità desiderata in anni per tornare indietro nel tempo:

@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

il /Fin cmd /c del @path /Fforza il file specifico da eliminare in alcuni casi il file può essere di sola lettura.

la dateYearè la variabile anno e non v'è possibile modificare la sottrarre alle proprie esigenze

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.