Pergunta

Estou procurando uma maneira de excluir todos os arquivos com mais de 7 dias em um arquivo em lote.Pesquisei na web e encontrei alguns exemplos com centenas de linhas de código e outros que exigiam a instalação de utilitários de linha de comando extras para realizar a tarefa.

Coisas semelhantes podem ser feito em BASH em apenas algumas linhas de código.Parece que algo pelo menos remotamente fácil poderia ser feito para arquivos em lote no Windows.Estou procurando uma solução que funcione em um prompt de comando padrão do Windows, sem utilitários extras.Por favor, também não use PowerShell ou Cygwin.

Foi útil?

Solução

Aproveitar:

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

Ver documentação do arquivo para mais detalhes.

Para mais guloseimas, consulte Um índice A-Z da linha de comando do Windows XP.

Se você não tem forfiles instalado em sua máquina, copie-o de qualquer Servidor Windows 2003 para sua máquina Windows XP em %WinDir%\system32\.Isso é possível porque o EXE é totalmente compatível entre o Windows Server 2003 e o Windows XP.

Versões posteriores do Windows e do Windows Server o possuem instalado por padrão.

Para Windows 7 e versões mais recentes (incluindo Windows 10):

A sintaxe mudou um pouco.Portanto o comando atualizado é:

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

Outras dicas

Execute o seguinte comandos:

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

Mova todos os arquivos (usando /mov, que move arquivos e os exclui, em oposição a /move, que move árvores de arquivos inteiras que são excluídas) via robocopy para outro local e, em seguida, execute um comando delete nesse caminho e você estará tudo bom.

Além disso, se você tiver um diretório com muitos dados, poderá usar /mir trocar

Ok, fiquei um pouco entediado e descobri isso, que contém minha versão de um substituto de época do Linux para um homem pobre, limitado para uso diário (sem retenção de tempo):

7 dias limpos.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 :Mudar 7 para o número de dias a serem mantidos.

set dSource=C:\temp :Este é o diretório inicial para verificar arquivos.

NOTAS

Este é um código não destrutivo, ele exibirá o que teria acontecido.

Mudar :

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

para algo como:

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

então os arquivos são realmente excluídos

Fevereiro:é codificado para 28 dias.Anos bissextos são um inferno para acrescentar, na verdade.se alguém tiver uma ideia que não adicionaria 10 linhas de código, vá em frente e poste para que eu adicione no meu código.

época:Não levei em consideração o tempo, pois a necessidade é deletar arquivos anteriores a uma determinada data, levar horas/minutos teria deletado arquivos de um dia que deveria ser guardado.

LIMITAÇÃO

época considera que seu formato de data abreviada é AAAA-MM-DD.Ele precisaria ser adaptado para outras configurações ou uma avaliação em tempo de execução (leia sShortTime, configuração vinculada ao usuário, configure a ordem adequada dos campos em um filtro e use o filtro para extrair os dados corretos do argumento).

Já mencionei que odeio a formatação automática deste editor?remove as linhas em branco e copiar e colar é um inferno.

Eu espero que isso ajude.

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

Você deveria fazer /d -3 (3 dias antes) Isso funciona bem para mim.Portanto, todos os lotes complicados poderiam estar na lixeira.Também forfiles não suportam caminhos UNC, portanto estabeleça uma conexão de rede com uma unidade específica.

Dê uma olhada no meu responder para um pergunta semelhante:

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"

Isso exclui arquivos anteriores a uma determinada data.Tenho certeza de que pode ser modificado para voltar sete dias a partir da data atual.

atualizar: Percebo que o HerbCSO melhorou o script acima.Eu recomendo usar a versão dele em vez de.

Meu comando é

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

@PATH - é apenas o caminho no meu caso, então tive que usar @PATH\@FILE

também forfiles /? não está funcionando para mim também, mas forfiles (sem "?") funcionou bem.

E a única dúvida que tenho:como adicionar múltiplas máscaras (por exemplo ".log|.bak")?

Tudo isso sobre forfiles.exe que eu baixado aqui (no ganhar XP)

Mas se você estiver usando o servidor Windows, forfiles.exe já deve estar lá e é diferente da versão ftp.É por isso que devo modificar o comando.

Para Windows Server 2003 estou usando este comando:

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

Para Windows Server 2008 R2:

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

Isso excluirá todos .sql arquivos mais antigos que 90 dias.

Copie este código e salve-o como DelOldFiles.vbs.

USO SOMENTE NO PROMPT DE COMANDO:cscript DelOldFiles.vbs 15

15 significa excluir arquivos com mais de 15 dias.

  '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

Use forfiles.

Existem diferentes versões.Os primeiros usam parâmetros de estilo unix.

Minha versão (para servidor 2000 - não observe espaço após as opções) -

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

Para adicionar forfiles ao XP, obtenha o exe em ftp://ftp.microsoft.com/ResKit/y2kfix/x86/

e adicione-o em C:\WINDOWS\system32

Para o Windows 2012 R2, o seguinte funcionaria:

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

para ver os arquivos que serão deletados use isto

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

IMO, JavaScript está gradualmente se tornando um padrão de script universal:provavelmente está disponível em mais produtos do que qualquer outra linguagem de script (no Windows, está disponível usando o Windows Scripting Host).Tenho que limpar arquivos antigos em muitas pastas, então aqui está uma função JavaScript para fazer isso:

// 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);
    }
}

Para limpar cada pasta, basta adicionar outra chamada à função clearFolder().Este código específico também preserva arquivos exe e dll e também limpa subpastas.

Que tal essa modificação em 7 dias limpos.cmd levar em conta um ano bissexto?

Isso pode ser feito em menos de 10 linhas de codificação!

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

Editado por Mofi:

A condição acima contribuiu por JR avalia sempre para falso por causa da sintaxe inválida.

E Month GEQ 2 também está errado porque a adição de 86.400 segundos para mais um dia deve ser feita em ano bissexto apenas para os meses de março a dezembro, mas não para fevereiro.

Um código funcional para levar em consideração o dia bissexto - apenas no ano atual - em arquivo em lote 7 dias limpos.cmd postado por Jay seria:

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

Muitas vezes há questões relacionadas a data/hora relativas para resolver com arquivo em lote.Mas o interpretador de linha de comando cmd.exe não tem função para cálculos de data/hora.Muitas boas soluções de trabalho usando aplicativos ou scripts de console adicionais já foram postadas aqui, em outras páginas do Stack Overflow e em outros sites.

Comum para operações baseadas em data/hora é o requisito de converter uma sequência de data/hora em segundos desde um determinado dia.Muito comum é 01/01/1970 00:00:00 UTC.Mas qualquer dia posterior também pode ser usado dependendo do intervalo de datas necessário para dar suporte a uma tarefa específica.

Jay postou 7 dias limpos.cmd contendo uma solução rápida de "data em segundos" para interpretador de linha de comando cmd.exe.Mas não leva em conta os anos bissextos corretamente. JR postou um adicionar para levar em consideração o dia bissexto do ano atual, mas ignorando os outros anos bissextos desde o ano base, ou seja,desde 1970.

Eu uso há 20 anos tabelas estáticas (matrizes) criadas uma vez com uma pequena função C para obter rapidamente o número de dias, incluindo dias bissextos de 01/01/1970 em funções de conversão de data/hora em meus aplicativos escritos em C/C++.

Este método de tabela muito rápido também pode ser usado em código em lote usando PARA comando.Então decidi codificar a sub-rotina em lote GetSeconds que calcula o número de segundos desde 1970-01-01 00:00:00 UTC para uma string de data/hora passada para esta rotina.

Observação: Os segundos bissextos não são levados em consideração porque os sistemas de arquivos do Windows também não suportam segundos bissextos.

Primeiro, as tabelas:

  1. Dias desde 1970-01-01 00:00:00 UTC para cada ano, incluindo dias bissextos.

    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
    

    O cálculo dos segundos para o ano de 2039 a 2106 com época começando em 01/01/1970 só é possível usando uma variável não assinada de 32 bits, ou seja,unsigned long (ou unsigned int) em C/C++.

    Mas cmd.exe use para expressões matemáticas uma variável assinada de 32 bits.Portanto, o valor máximo é 2147483647 (0x7FFFFFFF), que é 2038-01-19 03:14:07.

  2. Informações sobre anos bissextos (Não/Sim) para os anos de 1970 a 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. Número de dias até o primeiro dia de cada mês no ano atual.

                       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
    

Converter uma data em número de segundos desde 01/01/1970 é bastante fácil usando essas tabelas.

Atenção por FAVOR!

O formato das strings de data e hora depende da região do Windows e das configurações de idioma.Os delimitadores e a ordem dos tokens atribuídos às variáveis ​​de ambiente Day, Month e Year primeiramente PARA ciclo de GetSeconds deve ser adaptado ao formato local de data/hora, se necessário.

É necessário adaptar a string de data da variável de ambiente se o formato de data na variável de ambiente DATA é diferente do formato de data usado pelo comando PARA sobre %%~tF.

Por exemplo quando %DATE% expande para Sun 02/08/2015 enquanto %%~tF expande para 02/08/2015 07:38 PM o código abaixo pode ser usado modificando a linha 4 para:

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

Isso resulta na passagem para a sub-rotina apenas 02/08/2015 - a sequência de data sem as 3 letras da abreviatura do dia da semana e o caractere de espaço de separação.

Alternativamente, o seguinte pode ser usado para passar a data atual no formato correto:

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

Agora os últimos 10 caracteres da string de data são passados ​​para a função GetSeconds e, portanto, não importa se a string de data da variável de ambiente DATA está com ou sem dia da semana, desde que o dia e o mês estejam sempre com 2 dígitos na ordem esperada, ou seja,em formato dd/mm/yyyy ou dd.mm.yyyy.

Aqui está o código em lote com comentários explicativos que apenas exibem qual arquivo excluir e qual arquivo manter C:\Temp árvore de pastas, veja o código do primeiro PARA laço.

@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

Para um desempenho ideal, seria melhor remover todos os comentários, ou seja,todas as linhas começando com rem após 0-4 espaços iniciais.

E as matrizes também podem ser menores, ou seja,diminuindo o intervalo de tempo de 1980-01-01 00:00:00 para 2038-01-19 03:14:07 conforme atualmente suportado pelo código de lote acima, por exemplo, para 2015-01-01 a 2019-12-31 como o código abaixo usa o que realmente exclui arquivos com mais de 7 dias em C:\Temp árvore de pastas.

Além disso, o código de lote abaixo é otimizado para o formato de 24 horas.

@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

Para obter ainda mais informações sobre formatos de data e hora e comparações de hora de arquivo no Windows, consulte minha resposta em Descubra se o arquivo tem mais de 4 horas em arquivo em lote com muitas informações adicionais sobre os tempos dos arquivos.

Posso acrescentar uma humilde contribuição a este já valioso tópico.Estou descobrindo que outras soluções podem eliminar o texto de erro real, mas estão ignorando o% ERRORLEVEL% que sinaliza uma falha em meu aplicativo.E eu quero legitimamente %ERRORLEVEL%, desde que não seja o erro "Nenhum arquivo encontrado".

Alguns exemplos:

Depurando e eliminando o erro especificamente:

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

Usando um oneliner para retornar sucesso ou falha de 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

Usando um oneliner para manter o ERRORLEVEL em zero para obter sucesso no contexto de um arquivo em lote no meio de outro código (ver > nul redefine o 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

Para uma etapa de trabalho do SQL Server Agent CmdExec, cheguei ao seguinte.Não sei se é bug, mas o CmdExec da etapa reconhece apenas a primeira linha do código:

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 você tiver o kit de recursos XP, poderá usar o robocopy para mover todos os diretórios antigos para um único diretório e, em seguida, usar rmdir para excluir apenas esse:

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

Eu penso resposta de e.James é bom porque funciona com versões não modificadas do Windows desde o Windows 2000 SP4 (e possivelmente anteriores), mas exigia a gravação em um arquivo externo.Aqui está uma versão modificada que não cria um arquivo de texto externo, mantendo a compatibilidade:

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)

Para ser fiel à pergunta original, aqui está um script que faz TODAS as contas para você se você chamá-lo com o número de dias como parâmetro:

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)

OBSERVAÇÃO:O código acima leva em consideração anos bissextos, bem como o número exato de dias de cada mês.O único máximo é o número total de dias desde 0/0/0 (depois disso retorna anos negativos).

OBSERVAÇÃO:A matemática só vai em um sentido;ele não pode obter datas futuras corretamente a partir de entradas negativas (ele tentará, mas provavelmente ultrapassará o último dia do mês).

Você pode conseguir fazer isso.Você pode dar uma olhada essa questão, para um exemplo mais simples.A complexidade surge quando você começa a comparar as datas.Pode ser fácil saber se a data é maior ou não, mas há muitas situações a serem consideradas se você realmente precisar obter a diferença entre duas datas.

Em outras palavras - não tente inventar isso, a menos que você realmente não possa usar ferramentas de terceiros.

isso não é nada incrível, mas eu precisava fazer algo assim hoje e executá-lo como tarefa agendada, etc.

arquivo em lote, DelFilesOlderThanNDays.bat abaixo com exemplo de exec com parâmetros:

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

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

Expandindo a resposta de aku, vejo muitas pessoas perguntando sobre os caminhos UNC.Simplesmente mapear o caminho unc para uma letra de unidade deixará os arquivos felizes.O mapeamento e o desmapeamento de unidades podem ser feitos programaticamente em um arquivo em lote, por exemplo.

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"

Isso excluirá todos os arquivos com extensão .gz com mais de 7 dias.Se você quiser ter certeza de Z:não está mapeado para mais nada antes de usá-lo, você poderia fazer algo simples como

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

Nossa, já há muitas respostas.Uma rota simples e conveniente que encontrei foi executar ROBOCOPY.EXE duas vezes em ordem sequencial a partir de uma única instrução de linha de comando do Windows usando o & parâmetro.

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

Neste exemplo funciona escolhendo todos os arquivos (.) com mais de 30 dias e movendo-os para a pasta de destino.O segundo comando faz o mesmo novamente com a adição do PURGA comando que significa remover arquivos na pasta de destino que não existem na pasta de origem.Então, essencialmente, o primeiro comando MOVE os arquivos e o segundo DELETES porque eles não existem mais na pasta de origem quando o segundo comando é invocado.

Consulte a documentação do ROBOCOPY e use a opção /L ao testar.

ROBOCOPIA funciona muito bem para mim.Originalmente sugeriu meu Iman.Mas em vez de mover os arquivos/pastas para um diretório temporário e excluir o conteúdo da pasta temporária, mova os arquivos para a lixeira!!!

Estas são algumas linhas do meu arquivo em lote de backup, por exemplo:

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

Ele limpa qualquer coisa com mais de 15 dias da minha pasta 'Temp' e 30 dias para qualquer coisa na minha pasta de backup do AutoCAD.Eu uso variáveis ​​porque a linha pode ficar bem longa e posso reutilizá-las para outros locais.Você só precisa encontrar o caminho dos para a lixeira associada ao seu login.

Isso está em um computador de trabalho para mim e funciona.Entendo que alguns de vocês podem ter direitos mais restritivos, mas tente mesmo assim;) Pesquise no Google explicações sobre os parâmetros ROBOCOPY.

Saúde!

Este fez isso por mim.Funciona com data e você pode subtrair o valor desejado em anos para voltar no 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

o /F no cmd /c del @path /F força a exclusão do arquivo específico em alguns casos em que o arquivo pode ser somente leitura.

o dateYear é o ano variável e aí você pode alterar o substrato de acordo com suas necessidades

Meu script para excluir arquivos anteriores a um ano específico:

@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
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top