Archivo por lotes para eliminar archivos con más de N días

Estoy buscando una forma de eliminar todos los archivos de más de 7 días en un archivo por lotes. Busqué en la web y encontré algunos ejemplos con cientos de líneas de código y otros que requerían la instalación de utilidades de línea de comandos adicionales para realizar la tarea.

Cosas similares pueden ser hecho en BASH en solo un par de líneas de código. Parece que se podría hacer algo al menos remotamente fácil para los archivos por lotes en Windows. Estoy buscando una solución que funcione en un símbolo del sistema de Windows estándar, sin utilidades adicionales. Tampoco PowerShell o Cygwin.

preguntado el 08 de septiembre de 08 a las 23:09

Jeff Atwood respondió esto en Serverfault, que creo que debería documentarse aquí. serverfault.com/questions/49614/delete-files-older-than-x-days -

Un nuevo método basado en un archivo .BAT que usa comandos CMD.EXE internos solo se ha publicado aquí: stackoverflow.com/questions/9746778/… -

gehrcke.de/timegaps ha sido diseñado para este propósito. Incluso permite un esquema de eliminación más sofisticado: además de mantener archivos de los últimos 7 días, por ejemplo, también permite mantener un archivo para cada una de las últimas 8 semanas, 12, meses, 2 años. -

25 Respuestas

Disfruta:

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

Ver forfiles documentación para más información.

Para más golosinas, consulte Un índice AZ de la línea de comandos de Windows XP.

Si no tienes forfiles instalado en su máquina, cópielo desde cualquier Windows Server 2003 a su máquina con Windows XP en %WinDir%\system32\. Esto es posible porque el EXE es totalmente compatible entre Windows Server 2003 y Windows XP.

Las versiones posteriores de Windows y Windows Server lo tienen instalado de forma predeterminada.

Para Windows 7 y versiones posteriores (incluido Windows 10):

La sintaxis ha cambiado un poco. Por lo tanto, el comando actualizado es:

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

Respondido 01 ago 19, 20:08

Debería ser del @FILE, el caso importa.También sugiero usar / c echo @FILE para probar - russell steen

@Russell: @PATH es la ruta completa, incluido el nombre. @FILE es solo el nombre, por lo que si está tratando con subcarpetas, no funcionará. - Gregmac

Tenga en cuenta que si desea archivos con una antigüedad de más de 10 días, debe especificar -d "-10". -ve significa "más antiguo que", + ve significa "más nuevo que". También puede especificar el formato DDMMYY o -DDMMYY como parámetro para -d. - Gregmac

Usé esta sintaxis en Win Server 2008: forfiles / P "C: \ Mysql_backup" / S / M * .sql / D -30 / C "cmd / c del @PATH" - jman

Esta respuesta funciona cuando "más de 7 días" se define como "modificado hace más de 7 días" en lugar de "creado hace más de 7 días". ¿Cómo se puede lograr esto último? - TimS

Ejecutar el siguiente comandos:

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

Mueva todos los archivos (usando / mov, que mueve archivos y luego los elimina en lugar de / move que mueve árboles de archivos completos que luego se eliminan) a través de robocopy a otra ubicación, y luego ejecute un comando de eliminación en esa ruta y estará todo bien.

Además, si tiene un directorio con muchos datos, puede usar /mir cambiar

Respondido 30 Oct 15, 03:10

En su mayor parte, esta es una respuesta poco práctica. Si tengo un directorio con muchos datos, no funcionará bien. Yo iría con una de las respuestas que lo hace "en su lugar" - adamb0mb

@ adamb0mb esto no es de ninguna manera impráctico, si "destino" está en el mismo sistema de archivos que "fuente", la operación de movimiento es bastante ligera. Como es robocopy democracia robusto, de hecho funcionará para cualquier tamaño de directorio, nombres de archivo oscuros, básicamente longitudes de ruta arbitrarias e incluye directorios si lo necesita, algo que seguramente no se puede decir sobre muchas otras utilidades de Windows. yo usaría rd /s /q c:\destination en vez de del aunque ordene o incluso use otro robocopy /mir c:\emptydir c:\destination ejecute para vaciar el directorio si espera problemas con los nombres de archivo. - Syneticon-dj

Además, robocopy admite rutas UNC, que forfiles de la respuesta aceptada no servirá. - Syneticon-dj

Mis pensamientos estaban más en la línea: "Mis archivos ya están donde los quiero. No quiero tener que moverlos". "Eliminar archivos es lógicamente lo que está haciendo, así que hágalo. No sobrecargue Robocopy para hacerlo" - adamb0mb

Recomiendo este resumen para ver todos los archivos en C:\test más de 7 días. Para eliminar los archivos, cambie el echo a del: forfiles /p "C:\test" /m "*.*" /c "cmd /c echo @file" /D -7 - Usuario de poder

Ok estaba un poco aburrido y se le ocurrió esto, que contiene mi versión del reemplazo de época de Linux de un hombre pobre limitado para uso diario (sin retención de tiempo):

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 : Cambio 7 por el número de días a conservar.

set dSource=C:\temp : Este es el directorio de inicio para buscar archivos.

NOTAS

Este es un código no destructivo, mostrará lo que hubiera sucedido.

Cambio:

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

a algo como:

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

para que los archivos realmente se eliminen

Febrero: está codificado en 28 días. Los años bissextiles son un infierno para agregar, de verdad. si alguien tiene una idea que no agregaría 10 líneas de código, adelante y publíquela para que la agregue a mi código.

época: No tomé en consideración el tiempo, ya que la necesidad es eliminar archivos anteriores a una fecha determinada, tomar horas / minutos habría eliminado archivos de un día que estaba destinado a conservar.

LIMITACIÓN

época da por sentado que su formato de fecha corta es AAAA-MM-DD. Debería adaptarse para otras configuraciones o una evaluación en tiempo de ejecución (lea sShortTime, configuración vinculada al usuario, configure el orden de campo adecuado en un filtro y use el filtro para extraer los datos correctos del argumento).

¿Mencioné que odio el formato automático de este editor? elimina las líneas en blanco y copiar y pegar es un infierno.

Espero que esto ayude.

Respondido el 15 de Septiembre de 17 a las 18:09

+1 para código no destructivo, intentaré tenerlo en cuenta cuando proporcione ejemplos de código. - haugholt

Muy tarde y sin ninguna relación, pero 7daysclean.cmd suena como un nombre impresionante para una banda de Synth-Punk. - Flok

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

Deberías hacer /d -3 (3 días antes) Esto funciona bien para mí. Entonces, todos los lotes complicados podrían estar en la papelera. También forfiles no son compatibles con las rutas UNC, por lo que debe realizar una conexión de red a una unidad específica.

Respondido 01 ago 13, 09:08

Mismo error que en otras respuestas (incluida la aceptada). ¿Dónde surgió este extraño hábito de especificar *.* ¿viene de? Comodín *.* no coincide con todos los archivos de Windows. Solo coincide con archivos con . en sus nombres. El OP nunca dijo nada sobre requerir . en el nombre del archivo. El parámetro adecuado es /M *, pero este es el valor predeterminado de todos modos. No hay necesidad de /M en absoluto. - Hormiga

@AnT: ¿Estás seguro? creo *.* se comporta exactamente como * en Windows. De hecho, lo probé en mi computadora y dir *.* de hecho enumerado test file, un archivo sin extensión. - andreas rejbrand

@Andreas Rejbrand: También me sorprende, pero el tratamiento de *.* es inconsistente entre, digamos, dir y -m opción de forfiles. -m *.* de hecho, la máscara omitirá los nombres de archivos sin extensión, como dije en mi comentario anterior (pruébelo usted mismo). La parte divertida aquí es que la documentación de MS establece explícitamente que -m *.* es el predeterminado. Sin embargo, si lo prueba en la vida real, verá que el valor predeterminado es en realidad -m * - todos los archivos se repiten. - Hormiga

Esta página de documentación de MS - technet.microsoft.com/en-us/library/cc753551(v=ws.11).aspx - contiene una gran cantidad de errores (por ejemplo, en ejemplos) porque el autor del documento creyó incorrectamente que *.* máscara aplicada a todos los archivos. Mi pregunta retórica sobre "este extraño hábito" fue, de hecho, innecesaria, ya que tratar *.* y * como equivalente es una convención de Windows de larga data. Sin emabargo, /m en opción forfiles Ocurre que viola esa convención por alguna razón. - Hormiga

Antecedentes sobre el 5 comodines en Windows: blogs.msdn.microsoft.com/jeremykuhne/2017/06/04/… - MSalters

Echa un vistazo a mi https://www.youtube.com/watch?v=xB-eutXNUMXJtA&feature=youtu.be a una pregunta similar:

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"

Esto elimina archivos anteriores a una fecha determinada. Estoy seguro de que se puede modificar para retroceder siete días desde la fecha actual.

actualizar: Noto que HerbCSO ha mejorado en el script anterior. Recomiendo usar su versión preferiblemente.

contestado el 23 de mayo de 17 a las 13:05

Mi comando es

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

@PATH - es solo camino en mi caso, así que tuve que usar @PATH\@FILE

además, forfiles /? no funciona para mí también, pero forfiles (sin "?") funcionó bien.

Y la única pregunta que tengo: cómo agregar varias máscaras (por ejemplo ".log |.bak ")?

Todo esto con respecto a forfiles.exe que yo descargar aquí (en ganar XP)

Pero si está utilizando el servidor de Windows, forfiles.exe ya debería estar allí y es diferente de la versión de ftp. Por eso debería modificar el comando.

Para Windows Server 2003 estoy usando este comando:

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

Respondido 01 ago 13, 09:08

Para Windows Server 2008 R2:

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

Esto borrará todo .sql archivos anteriores a 90 día.

Respondido 27 Abr '12, 23:04

Muy a menudo hay preguntas relativas a la fecha / hora que se deben resolver con el archivo por lotes. Pero intérprete de línea de comando cmd.exe no tiene función para los cálculos de fecha / hora. Ya se han publicado muchas buenas soluciones que utilizan aplicaciones de consola o scripts adicionales aquí, en otras páginas de Stack Overflow y en otros sitios web.

Común para las operaciones basadas en fecha / hora es el requisito de convertir una cadena de fecha / hora en segundos desde un día determinado. Muy común es 1970-01-01 00:00:00 UTC. Pero también se podría usar cualquier día posterior según el rango de fechas requerido para respaldar una tarea específica.

arrendajo publicado 7daysclean.cmd que contiene una solución rápida de "fecha a segundos" para el intérprete de línea de comandos cmd.exe. Pero no tiene en cuenta los años bisiestos. JR depositado add-on por tener en cuenta los días bisiestos del año en curso, pero ignorando los demás años bisiestos desde el año base, es decir, desde 1970.

Utilizo desde hace 20 años tablas estáticas (matrices) creadas una vez con una pequeña función C para obtener rápidamente la cantidad de días, incluidos los días bisiestos, de 1970-01-01 en funciones de conversión de fecha / hora en mis aplicaciones escritas en C / C ++.

Este método de tabla muy rápido se puede utilizar también en código de lote utilizando mando. Entonces decidí codificar la subrutina por lotes GetSeconds que calcula el número de segundos desde 1970-01-01 00:00:00 UTC para una cadena de fecha / hora pasada a esta rutina.

Nota: Los segundos intercalares no se tienen en cuenta, ya que los sistemas de archivos de Windows tampoco admiten los segundos intercalares.

Primero, las tablas:

  1. Días desde 1970-01-01 00:00:00 UTC para cada año, incluidos los días bisiestos.

    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
    

    El cálculo de los segundos para el año 2039 a 2106 con época que comienza 1970-01-01 solo es posible con el uso de una variable de 32 bits sin signo, es decir, unsigned long (o unsigned int) en C / C ++.

    Pero cmd.exe utilice para expresiones matemáticas una variable de 32 bits con signo. Por lo tanto, el valor máximo es 2147483647 (0x7FFFFFFF) que es 2038-01-19 03:14:07.

  2. Información de años bisiestos (No / Sí) para los años 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 días hasta el primer día de cada mes del año actual.

                       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
    

Convertir una fecha en un número de segundos desde 1970-01-01 es bastante fácil usando esas tablas.

¡Atención por favor!

El formato de las cadenas de fecha y hora depende de la región de Windows y la configuración de idioma. Los delimitadores y el orden de los tokens asignados a las variables de entorno. Day, Month y Year en primer bucle de GetSeconds debe adaptarse al formato de fecha / hora local si es necesario.

Es necesario adaptar la cadena de fecha de la variable de entorno si el formato de fecha en la variable de entorno FECHA es diferente al formato de fecha utilizado por el comando on %%~tF.

Por ejemplo cuando %DATE% se expande a Sun 02/08/2015 mientras %%~tF se expande a 02/08/2015 07:38 PM el código siguiente se puede utilizar con la modificación de la línea 4 a:

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

Esto resulta en pasar a la subrutina solo 02/08/2015 - la cadena de fecha sin las 3 letras de la abreviatura del día de la semana y el carácter de espacio de separación.

Alternativamente, se podría usar lo siguiente para pasar la fecha actual en el formato correcto:

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

Ahora los últimos 10 caracteres de la cadena de fecha se pasan a la función GetSeconds y por lo tanto no importa si la cadena de fecha de la variable de entorno FECHA es con o sin día de la semana siempre que el día y el mes tengan siempre 2 dígitos en el orden esperado, es decir, en formato dd/mm/yyyy or dd.mm.yyyy.

Aquí está el código de lote con comentarios explicativos que solo muestran qué archivo eliminar y qué archivo mantener C:\Temp árbol de carpetas, consulte el código de la primera lazo.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
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=" %%# in ('dir /A-D-H-S /B /S "C:\Temp"') do (
    call :GetSeconds "%%~t#:0"
    set "FullFileName=%%#"
    setlocal EnableDelayedExpansion
    rem if !Seconds! LSS %LastWeek% del /F "!FullFileName!"
    if !Seconds! LEQ %LastWeek% (
        echo Delete "!FullFileName!"
    ) else (
        echo Keep   "!FullFileName!"
    )
    endlocal
)
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 not "%DateTime: AM=%" == "%DateTime%" (
    set "DateTime=%DateTime: AM=%"
) else if not "%DateTime: PM=%" == "%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%"  == "0" if not "%Month:~1%"  == "" set "Month=%Month:~1%"
if "%Day:~0,1%"    == "0" if not "%Day:~1%"    == "" set "Day=%Day:~1%"
if "%Hour:~0,1%"   == "0" if not "%Hour:~1%"   == "" set "Hour=%Hour:~1%"
if "%Minute:~0,1%" == "0" if not "%Minute:~1%" == "" set "Minute=%Minute:~1%"
if "%Second:~0,1%" == "0" if not "%Second:~1%" == "" 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 two 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 un rendimiento óptimo, sería mejor eliminar todos los comentarios, es decir, todas las líneas que comienzan con rem después de 0-4 espacios iniciales.

Y las matrices también se pueden hacer más pequeñas, es decir, disminuyendo el rango de tiempo de 1980-01-01 00:00:00 a 2038-01-19 03:14:07 como lo admite actualmente el código de lote anterior, por ejemplo, a 2015-01 -01 a 2019-12-31 ya que el código a continuación utiliza, que realmente elimina archivos de más de 7 días en C:\Temp árbol de carpetas.

Además, el siguiente código de lote está optimizado para formato de 24 horas.

@echo off
setlocal EnableExtensions DisableDelayedExpansion
call :GetSeconds "%DATE:~-10% %TIME%"
set /A "LastWeek=Seconds-7*86400"

for /F "delims=" %%# in ('dir /A-D-H-S /B /S "C:\Temp"') do (
    call :GetSeconds "%%~t#:0"
    set "FullFileName=%%#"
    setlocal EnableDelayedExpansion
    if !Seconds! LSS %LastWeek% del /F "!FullFileName!"
    endlocal
)
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%"  == "0" if not "%Month:~1%"  == "" set "Month=%Month:~1%"
if "%Day:~0,1%"    == "0" if not "%Day:~1%"    == "" set "Day=%Day:~1%"
if "%Hour:~0,1%"   == "0" if not "%Hour:~1%"   == "" set "Hour=%Hour:~1%"
if "%Minute:~0,1%" == "0" if not "%Minute:~1%" == "" set "Minute=%Minute:~1%"
if "%Second:~0,1%" == "0" if not "%Second:~1%" == "" 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 obtener aún más información sobre los formatos de fecha y hora y las comparaciones de tiempo de archivo en Windows, consulte mi respuesta en Averigüe si el archivo tiene más de 4 horas en el archivo por lotes con mucha información adicional sobre los tiempos de los archivos.

Respondido 01 Feb 21, 08:02

Para Windows 2012 R2, funcionaría lo siguiente:

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

para ver los archivos que se eliminarán utilice este

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

Respondido 25 Jul 15, 16:07

Esto incluso funciona en Windows Server 2008 y superior y Windows 7. - kwrl

Copie este código y guárdelo como DelOldFiles.vbs.

USO EN CMD: cscript //nologo DelOldFiles.vbs 15

15 significa eliminar archivos con más de 15 días de antigüedad.

  '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

Respondido 27 ago 19, 09:08

Utilice forfiles.

Existen diferentes versiones. Los primeros usan parámetros de estilo Unix.

Mi versión (para el servidor 2000 - tenga en cuenta que no hay espacio después de los interruptores) -

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

Para agregar archivos forfiles a XP, obtenga el exe de ftp://ftp.microsoft.com/ResKit/y2kfix/x86/

y agréguelo a C: \ WINDOWS \ system32

respondido 14 nov., 11:15

@Kibbee no es la misma respuesta, la sintaxis es diferente. Este fue un intento genuino de ayudar. Sabiendo muy poco de la línea de comandos de Windows, pasé horas de frustración haciendo que esto funcionara. La información clave para mí fue el hecho de que hay diferentes versiones (con diferente sintaxis) y que necesitaba eliminar los espacios. Ninguna de estas cosas se incluyó en la respuesta original. (Habría comentado la respuesta pero no tengo los privilegios - Aidan Ewen

Mismo error que en otras respuestas (incluida la aceptada). Comodín *.* in forfiles no coincide todos archivos. Solo coincide con archivos con . en sus nombres (es decir, archivos con extensiones). El OP nunca dijo nada sobre requerir . en el nombre del archivo. El parámetro adecuado es /M *, pero este es el valor predeterminado de todos modos. No hay necesidad de /M en absoluto. - Hormiga

En mi opinión, JavaScript se está convirtiendo gradualmente en un estándar de scripting universal: probablemente esté disponible en más productos que cualquier otro lenguaje de scripting (en Windows, está disponible usando Windows Scripting Host). Tengo que limpiar archivos antiguos en muchas carpetas, así que aquí hay una función de JavaScript para hacer eso:

// 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 que se borre cada carpeta, simplemente agregue otra llamada a la función clearFolder (). Este código en particular también conserva los archivos exe y dll, y también limpia las subcarpetas.

Respondido 26 Abr '13, 11:04

¿Qué tal esta modificación en 7daysclean.cmd tener en cuenta un año bisiesto?

¡Se puede hacer en menos de 10 líneas de codificación!

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

Editar por Mofi:

La condición anterior contribuida por JR evalúa siempre a false debido a una sintaxis no válida.

Y Month GEQ 2 También es incorrecto porque agregar 86400 segundos para un día más debe hacerse en un año bisiesto solo para los meses de marzo a diciembre, pero no para febrero.

Un código de trabajo para tener en cuenta los días bisiestos, solo en el año en curso, en el archivo por lotes 7daysclean.cmd publicado por arrendajo sería:

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

contestado el 23 de mayo de 17 a las 13:05

¿Puedo agregar una humilde contribución a este ya valioso hilo? Descubro que otras soluciones pueden eliminar el texto de error real, pero ignoran el% ERRORLEVEL% que indica un error en mi aplicación. Y legítimamente quiero% ERRORLEVEL% siempre que no sea el error "No se encontraron archivos".

Algunos ejemplos:

Depurar y eliminar el error específicamente:

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 un delineador para devolver ERRORLEVEL éxito o fracaso:

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

Usar un delineador para mantener ERRORLEVEL en cero para tener éxito dentro del contexto de un archivo por lotes en medio de otro código (ver> nul restablece 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 un paso de trabajo CmdExec del Agente SQL Server, llegué a lo siguiente. No sé si es un error, pero CmdExec dentro del paso solo reconoce la primera línea de 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%

Respondido 08 Abr '15, 14:04

Dios, ya hay muchas respuestas. Una ruta simple y conveniente que encontré fue ejecutar ROBOCOPY.EXE dos veces en orden secuencial desde una sola instrucción de línea de comando de Windows usando el & parámetro.

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

En este ejemplo, funciona seleccionando todos los archivos (.) que tienen más de 30 días y los mueve a la carpeta de destino. El segundo comando vuelve a hacer lo mismo con la adición del PURGA comando que significa eliminar archivos en la carpeta de destino que no existen en la carpeta de origen. Básicamente, el primer comando MOVIE archivos y el segundo ELIMINA porque ya no existen en la carpeta de origen cuando se invoca el segundo comando.

Consulte la documentación de ROBOCOPY y use el interruptor / L cuando realice la prueba.

Respondido 16 Abr '19, 08:04

Si tiene el kit de recursos de XP, puede usar robocopy para mover todos los directorios antiguos a un solo directorio, luego use rmdir para eliminar solo ese:

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

Respondido el 08 de diciembre de 10 a las 00:12

Creo que el e.La respuesta de James es bueno ya que funciona con versiones no modificadas de Windows desde Windows 2000 SP4 (y posiblemente antes), pero requería escribir en un archivo externo. Aquí hay una versión modificada que no crea un archivo de texto externo mientras mantiene la compatibilidad:

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 a la pregunta original, aquí está en un script que hace TODAS las matemáticas por usted si lo llama con el número de días 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)

NOTA: El código anterior tiene en cuenta los años bisiestos, así como el número exacto de días de cada mes. El único máximo es el número total de días que han pasado desde 0/0/0 (después de eso, devuelve años negativos).

NOTA: Las matemáticas solo funcionan en una dirección; no puede obtener correctamente las fechas futuras de la entrada negativa (lo intentará, pero probablemente pasará del último día del mes).

contestado el 23 de mayo de 17 a las 13:05

Robocopy funciona muy bien para mí. Originalmente sugirió mi Iman. Pero en lugar de mover los archivos / carpetas a un directorio temporal y luego eliminar el contenido de la carpeta temporal, mueva los archivos a la papelera !!!

Estas son algunas líneas de mi archivo por lotes de respaldo, por ejemplo:

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

Limpia todo lo que tenga más de 15 días de mi carpeta 'Temp' y 30 días para cualquier cosa en mi carpeta de copia de seguridad de AutoCAD. Utilizo variables porque la línea puede ser bastante larga y puedo reutilizarlas para otras ubicaciones. Solo necesita encontrar la ruta dos a su papelera de reciclaje asociada con su inicio de sesión.

Esto está en una computadora de trabajo para mí y funciona. Entiendo que algunos de ustedes pueden tener derechos más restrictivos, pero pruébenlo de todos modos;) Busque en Google explicaciones sobre los parámetros de ROBOCOPY.

¡Aclamaciones!

Respondido 15 ago 16, 16:08

La existencia segunda respuesta más votada también defiende RoboCopy. Por supuesto, usa opciones algo diferentes, pero se acerca a la respuesta existente. - jonathan leffler

Esta publicación tiene un contenido nuevo: mover archivos a la papelera de reciclaje. Esto aún no se ha propuesto con Robocopy y responde completamente a la publicación original utilizando un comando integrado de una sola línea. Funciona mejor que combinar los comandos 'DEL' y 'RMDIR' porque los archivos se pueden restaurar desde la papelera de reciclaje. Oye, todavía soy nuevo aquí, dame un respiro;) - shawn pauliszyn

Es posible que pueda lograrlo. Puedes echar un vistazo a esta pregunta, por un ejemplo más simple. La complejidad surge cuando comienzas a comparar las fechas. Puede ser fácil saber si la fecha es mayor o no, pero hay muchas situaciones a considerar si realmente necesita obtener la diferencia entre dos fechas.

En otras palabras, no intente inventar esto, a menos que realmente no pueda usar las herramientas de terceros.

contestado el 23 de mayo de 17 a las 13:05

esto no es nada sorprendente, pero necesitaba hacer algo como esto hoy y ejecutarlo como tarea programada, etc.

archivo por lotes, DelFilesOlderThanNDays.bat a continuación con ejemplo de ejecución w / params:

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

Respondido el 19 de diciembre de 13 a las 00:12

Ampliando la respuesta de aku, veo a mucha gente preguntando sobre las rutas UNC. Simplemente mapear la ruta unc a una letra de unidad hará feliz a forfiles. La asignación y anulación de la asignación de unidades se puede realizar mediante programación en un archivo por lotes, por ejemplo.

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"

Esto eliminará todos los archivos con una extensión .gz que tengan más de 7 días. Si desea asegurarse de que Z: no esté asignado a ninguna otra cosa antes de usarlo, puede hacer algo simple 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!"
)

respondido 14 mar '14, 10:03

Este lo hizo por mí. Funciona con una fecha y puedes restar la cantidad deseada en años para retroceder en el tiempo:

@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

el /F en la cmd /c del @path /F obliga a eliminar el archivo específico en algunos casos, el archivo puede ser de solo lectura.

el dateYear es el año Variable y allí puedes cambiar el sustrato a tus propias necesidades

contestado el 19 de mayo de 17 a las 09:05

Mi script para eliminar archivos anteriores a un año 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

Respondido 15 Jul 17, 10:07

Una forma más flexible es utilizar FileTimeFilterJS.bat:

@echo off

::::::::::::::::::::::
set "_DIR=C:\Users\npocmaka\Downloads"
set "_DAYS=-5"
::::::::::::::::::::::

for /f "tokens=* delims=" %%# in ('FileTimeFilterJS.bat  "%_DIR%" -dd %_DAYS%') do (
    echo deleting  "%%~f#"
    echo del /q /f "%%~f#"
)

El script le permitirá utilizar medidas como días, minutos, segundos u horas. Para elegir el clima para filtrar los archivos por hora de creación, acceso o modificación Para listar archivos antes o después de una fecha determinada (o entre dos fechas) Para elegir si mostrar archivos o directorios (o ambos) Para ser recursivo o no

respondido 12 nov., 20:09

Eliminar todos los archivos de más de 3 días

forfiles -p "C:\folder" -m *.* -d -3 -c "cmd  /c del /q @path"

Eliminar directorios de más de 3 días

forfiles -p "C:\folder" -d -3 -c "cmd  /c IF @isdir == TRUE rd /S /Q @path"

Respondido 24 Feb 21, 01:02

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.