Domanda

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 altri che richiedevano l'installazione di utilità della riga di comando aggiuntive per eseguire l'attività.

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

È stato utile?

Soluzione

Godere:

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

Vedere documentazione in archivio per ulteriori dettagli.

Per ulteriori chicche, fare riferimento a Un indice A-Z della riga di comando di Windows XP.

Se non hai forfiles installato sul tuo computer, copialo da qualsiasi WindowsServer2003 al tuo computer Windows XP all'indirizzo %WinDir%\system32\.Ciò è possibile poiché l'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 è leggermente cambiata.Pertanto il comando aggiornato è:

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

Altri suggerimenti

Esegui quanto segue 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 elimina invece di /move che sposta interi alberi di 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 al suo interno, puoi utilizzare /mir interruttore

Ok, mi sono annoiato un po' e ho pensato a questo, che contiene la mia versione di un sostituto dell'epoca di Linux per poveri limitato all'uso quotidiano (senza ritenzione di tempo):

7 giorni pulito. 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

UTILIZZO

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.

Modifica :

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

a qualcosa del tipo:

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

quindi i file vengono effettivamente eliminati

Febbraio:è hardcoded a 28 giorni.Gli anni bisessuali sono un inferno da aggiungere, davvero.se qualcuno ha un'idea che non richiede l'aggiunta di 10 righe di codice, vai avanti e pubblicala, così la aggiungo al mio codice.

epoca:Non ho preso in considerazione il tempo, poiché la necessità è di eliminare file più vecchi di una certa data, impiegare ore/minuti avrebbe eliminato i file di un giorno che doveva essere conservato.

LIMITAZIONE

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

Ho già detto che odio la formattazione automatica 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) Per me funziona bene.Quindi tutti i lotti complicati potrebbero finire nel cestino.Anche forfiles non supportano i percorsi UNC, quindi effettua una connessione di rete a un'unità specifica.

Dai un'occhiata al mio risposta ad a 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 possa essere modificato per tornare indietro di sette giorni dalla data corrente.

aggiornamento: Ho notato che HerbCSO ha migliorato lo script sopra.Consiglio di utilizzare la sua versione Invece.

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 usarlo @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 quanto riguarda forfiles.exe che I scaricato qui (su vinci XP)

Ma se stai utilizzando il server Windows, forfiles.exe dovrebbe essere già presente ed è diverso dalla versione ftp.Ecco perché dovrei modificare command.

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à tutto .sql file più vecchi di 90 giorni.

Copia questo codice e salvalo come DelOldFiles.vbs.

UTILIZZO SOLO NEL PROMPT DEI COMANDI:cscript DelOldFiles.vbs 15

15 significa eliminare file più vecchi di 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<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

Usa forfiles.

Esistono diverse versioni.I primi utilizzano parametri di stile Unix.

La mia versione (per server 2000 - nota che non c'è spazio dopo gli interruttori)-

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

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

e aggiungilo a C:\WINDOWS\system32

Per Windows 2012 R2 funzionerebbe quanto segue:

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

per vedere i file che verranno eliminati utilizzare questo

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

IMO, JavaScript sta gradualmente diventando uno standard di scripting universale: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 preserva anche i file exe e dll e ripulisce anche le sottocartelle.

Che ne dici di questa modifica? 7 giorni pulito. cmd 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 J.R. valuta sempre a falso a causa di una sintassi non valida.

E Month GEQ 2 è sbagliato anche perché l'aggiunta di 86400 secondi per un giorno in più deve essere fatta 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 7 giorni pulito. 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

Molto spesso ci sono domande relative a data/ora da risolvere con il file batch.Ma interprete della riga di comando cmd.exe non ha alcuna funzione per i calcoli di data/ora.Molte buone soluzioni funzionanti che utilizzano applicazioni console o script 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 è la necessità di convertire una stringa di data/ora in secondi a partire da un determinato giorno.Molto comune è 1970-01-01 00:00:00 UTC.Ma è possibile utilizzare anche qualsiasi giorno successivo a seconda dell'intervallo di date richiesto per supportare un'attività specifica.

Jay pubblicato 7 giorni pulito. cmd contenente una soluzione veloce "data in secondi" per l'interprete della riga di comando cmd.exe.Ma non tiene conto degli anni bisestili. J.R. ha pubblicato un Aggiungi su per prendere in considerazione il giorno bisestile dell'anno corrente, ma ignorando gli altri anni bisestili dall'anno base, cioèdal 1970.

Utilizzo 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 01-01-1970 nelle funzioni di conversione data/ora nelle mie applicazioni scritte in C/C++.

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

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

Innanzitutto le tabelle:

  1. Giorni dal 01-01-1970 alle 00:00:00 UTC per ogni anno compresi 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 l'epoca che inizia dal 01-01-1970 è possibile solo utilizzando una variabile a 32 bit senza segno, ovverounsigned long (o unsigned int) in C/C++.

    Ma cmd.exe utilizzare per le espressioni matematiche una variabile con segno a 32 bit.Pertanto il valore massimo è 2147483647 (0x7FFFFFFF) che è 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 fino al primo giorno di ogni mese dell'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
    

Convertire una data in numero di secondi dal 1970-01-01 è abbastanza semplice utilizzando 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 per primo PER ciclo di GetSeconds se necessario, deve essere adattato al formato data/ora locale.

È necessario adattare la stringa della data della variabile di ambiente se il formato della data è nella variabile di ambiente DATA è diverso dal formato della data utilizzato dal comando PER SU %%~tF.

Ad esempio quando %DATE% si espande a Sun 02/08/2015 Mentre %%~tF si espande a 02/08/2015 07:38 PM il codice seguente può essere utilizzato modificando la riga 4 in:

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

Ciò si traduce nel passaggio solo alla subroutine 02/08/2015 - la stringa della data senza le 3 lettere dell'abbreviazione del giorno feriale e il carattere di separazione.

In alternativa è possibile utilizzare quanto segue per passare la data corrente nel formato corretto:

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

Ora gli ultimi 10 caratteri della stringa della data vengono passati alla funzione GetSeconds e quindi non importa se è una stringa di data della variabile di ambiente DATA è con o senza giorno della settimana purché giorno e mese siano sempre con 2 cifre nell'ordine previsto, ad es.nel formato dd/mm/yyyy O dd.mm.yyyy.

Ecco il codice batch con commenti esplicativi che indica semplicemente quale file eliminare e quale file conservare C:\Temp albero delle cartelle, vedere il codice di first PER ciclo continuo.

@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, ad es.tutte le righe che iniziano con rem dopo 0-4 spazi iniziali.

E gli array possono essere resi anche più piccoli, ad es.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, dal 2015-01-01 al 2019-12-31 come il codice seguente utilizza che elimina realmente i file più vecchi di 7 giorni C:\Temp albero delle cartelle.

Inoltre, il codice batch riportato 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 sui confronti dell'ora dei file su Windows, vedere la mia risposta su Scopri se il file è più vecchio di 4 ore nel file batch con molte informazioni aggiuntive sui tempi dei file.

Potrei aggiungere un umile contributo a questo thread già prezioso.Sto scoprendo che altre soluzioni potrebbero eliminare il testo dell'errore effettivo ma ignorano %ERRORLEVEL% che segnala un errore nella mia applicazione.E desidero legittimamente %ERRORLEVEL% purché non si tratti dell'errore "Nessun file trovato".

Qualche esempio:

Debug ed eliminazione dell'errore in modo specifico:

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 ERRORLEVEL successo o fallimento:

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 per il successo nel contesto di un file batch in mezzo ad 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 di lavoro CmdExec di SQL Server Agent sono arrivato a quanto segue.Non so se è un bug, ma il 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%

Se disponi del Resource Kit di XP, puoi 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 /q c:\temp\OldDirectoriesGoHere

Penso La risposta di e.James è buono poiché funziona con versioni non modificate di Windows già a partire da Windows 2000 SP4 (e forse anche precedenti), ma richiedeva la scrittura su un file esterno.Ecco una versione modificata che non crea un file di testo esterno pur 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 qui in uno script che fa TUTTI i conti per te se lo 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 riportato sopra tiene conto degli anni bisestili, nonché del numero esatto di giorni in ciascun mese.L'unico massimo è il numero totale di giorni trascorsi dal 0/0/0 (dopodiché restituisce anni negativi).

NOTA:La matematica va solo in una direzione;non può ottenere correttamente le date future da un input negativo (ci proverà, ma probabilmente supererà l'ultimo giorno del mese).

Potresti riuscire a farcela.Puoi dare un'occhiata 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 possa davvero utilizzare gli strumenti di terze parti.

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

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

DelFilesOlderThanNDays.bat 7 C:\dir1\dir2\dir3\logs *.tronco d'albero

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

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à felice forfiles.La mappatura e l'annullamento della mappatura delle unità possono essere eseguite a livello di programmazione 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 più vecchi di 7 giorni.Se vuoi assicurarti che Z:non è mappato su nient'altro prima di usarlo potresti fare qualcosa di semplice come

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

Cavolo, già un sacco di risposte.Un percorso semplice e conveniente che ho trovato è stato eseguire ROBOCOPY.EXE due volte in ordine sequenziale da una singola istruzione della riga di comando di Windows utilizzando il comando & 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 (.) risalenti a più di 30 giorni prima e spostandoli nella cartella di destinazione.Il secondo comando fa nuovamente la stessa cosa con l'aggiunta del file EPURAZIONE comando che significa rimuovere i file nella cartella di destinazione che non esistono nella cartella di origine.Quindi, in sostanza, il primo comando SPOSTA i file e il secondo ELIMINA perché non esistono più nella cartella di origine quando viene richiamato il secondo comando.

Consulta la documentazione di ROBOCOPY e utilizza l'opzione /L durante il test.

ROBOCOPIA funziona benissimo per me.Inizialmente suggerito dal mio Iman.Ma invece di spostare i file/cartelle in una directory temporanea e poi eliminare il contenuto della cartella temporanea, sposta 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

Ripulisce qualsiasi cosa più vecchia di 15 giorni dalla mia cartella "Temp" e qualsiasi cosa risalente a 30 giorni fa nella mia cartella di backup di AutoCAD.Utilizzo le variabili perché la linea può diventare piuttosto lunga e posso riutilizzarle per altre posizioni.Devi solo trovare il percorso DOS del cestino associato al tuo login.

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

Saluti!

Questo lo ha fatto per me.Funziona con una data e puoi sottrarre l'importo desiderato 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 /F nel cmd /c del @path /F forza l'eliminazione del file specifico in alcuni casi in cui il file può essere di sola lettura.

IL dateYear è l'anno Variabile e lì puoi modificare la sottrazione in base alle tue esigenze

Il mio script per eliminare 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
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top