How to compress all files with exception of newest file in each subfolder of a folder into one ZIP file per subfolder?

醉酒当歌 提交于 2021-02-10 05:20:10

问题


I'm trying to create a batch script that will zip all the contents in each subdirectory except the latest (or latest few). I'm currently attempting in Windows with 7-Zip but the directory is technically on a Linux server so any suggestions geared towards a Linux command is welcome.

The directory structure is like this:

Directory-Parent
 ---Sub-Directory-1
 --------File1
 --------File2
 --------File3
 ---Sub-Directory-2
 --------File1
 --------File2

I would like to run a batch at the Directory-Parent level that will create a zip in each sub-directory of all the files except the latest 1 (or few if possible). I also want to add the year to the end of the zip file name.

So the result would be:

Directory-Parent
 -Sub-Directory-1
 --------File1
 --------Sub-Directory-12019.zip
 ---Sub-Directory-2
 --------File1
 --------Sub-Directory-22019.zip

I've tried a nested for loop but can't seem to get it. I've tried the for command with skip and dir in the set (IN), but can't get it to work.

I currently have the following script.

SET theYear=2019
For /D %%d in (*.*) do 7z a "%%d\%%d%theYear%.zip" ".\%%d\*"

This accomplishes it all except I don't know how to exclude the latest file (newest file according to last modification time) in each folder.


回答1:


This batch file can be used for this task:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FilesToIgnore=1"
set "theYear=%DATE:~-4%"
set "ListFile=%Temp%\%~n0.lst"
del "%ListFile%" 2>nul
for /D %%I in (*) do call :CompressFiles "%%I"
goto EndBatch

:CompressFiles
pushd %1
set "ZipFile=%~nx1%theYear%.zip"
for /F "skip=%FilesToIgnore% eol=| delims=" %%J in ('dir /A-D /B /O-D /TW 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /C:"%ZipFile%"') do >>"%ListFile%" echo %%J
if exist "%ListFile%" (
    echo Compressing files in directory %1 ...
    7z.exe a -bd -bso0 -i"@%ListFile%" -mx9 -scsDOS -- "%ZipFile%"
    del "%ListFile%"
)
popd
goto :EOF

:EndBatch
endlocal

The batch file sets environment variable theYear dynamically from region dependent date string of dynamic environment variable DATE. Please execute in a command prompt window echo %DATE:~-4% and verify if output is the current year because of echo %DATE% outputs current local date with last four characters being the year.

The batch file ignores the FilesToIgnore newest files in each directory. Ignored is also the ZIP file if already existing from a previous execution of the batch file. The ZIP file is never included in number of FilesToIgnore because of filtered out already by findstr which filters output of command dir which outputs the file names without path in current directory ordered by last modification time with newest files output first and oldest files output last.

Please read help of 7-Zip for the used switches and parameters.

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

  • del /?
  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • popd /?
  • pushd /?
  • set /?
  • setlocal /?

Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on FOR command line to be interpreted as literal characters when Windows command interpreter processes this command line before executing command FOR which executes the embedded command line in a separate command process started in background.

Update: 7-Zip version 19.00.0.0 outputs a warning and creates an empty ZIP file in each subdirectory on using the command line as written below and used initially in batch file. I first thought this is a bug of 7-Zip version 19.00.0.0 because of this version should support also -- according to its help and 7-Zip version 16.04.0.0 works on using the command line:

7z.exe a -bd -bso0 -mx9 -scsDOS -- "%ZipFile%" "@%ListFile%"

It was necessary to remove -- from this command line to get it working with 7-Zip version 19.00.0.0.

So I reported this issue and the author of 7-Zip quickly replied explaining why the usage of -- results in searching for a file starting with @ in file name since 7-Zip version 19.00.0.0:

We need some way to add @file and -file names from command line.
So -- stops @ and - parsing, and 7-Zip searches exact names.
It's more safe to use -i@listfile instead.

So I updated the batch file code and specify the list file with option -i which is the most safe method to specify a list file.




回答2:


The following code is completely untested, so please be careful when executing:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "ROOT=Directory-Parent" & rem /* (set this to `%~dp0.` to specify the parent directory of the
                              rem     batch file, or to `.` to for current working directory) */
set "YEAR=2019"  & rem // (set the year just as a constant as it is unclear where to get it from)
set "MOVA="      & rem // (set this to `-sdel` if you want the files to be moved into the archive)

rem // Interate through the current working directory:
for /D %%d in ("%ROOT%\*.*") do (
    rem // Clear exclusion parameter for `7z`, reset flag that indicates if there are files left:
    set "EXCL=" & set "FLAG="
    rem /* Iterate through all files in the currently iterated directory, sorted from 
    rem    oldest to newest (`/O:D`), regarding the last modification date/time (`/T:W`);
    rem    the `findstr` part is to exclude the archive file itself if already present: */
    for /F "delims= eol=|" %%f in ('
        dir /B /A:-D /O:D /T:W "%%~d\*.*" ^| findstr /V /I /X /C:"%%~nxd%YEAR%.zip"
    ') do (
        rem // Exclusion parameter is not yet set in first loop iteration:
        if defined EXCL set "FLAG=#"
        rem // Exclusion parameter becomes set at this point:
        set "EXCL=-x!"%%f""
    )
    rem /* Flag is only set if there is one more file besides the one to exclude,
    rem    meaning that there are at least two files in total: */
    if defined FLAG (
        rem // Store folder information in variables to avoid loss of potentially occurring `!`:
        set "FOLDER=%%~fd" & set "NAME=%%~nxd"
        rem /* Toggle delayed expansion in order to be able to read variables that have been
        rem    set within the same block of parenthesised code (namely the `for` loops): */
        setlocal EnableDelayedExpansion
        rem // Execute the `7z` command line with dynamic parameters:
        ECHO 7z a -bd %MOVA% !EXCL! -x^^!"!NAME!%YEAR%.zip" "!FOLDER!\!NAME!%YEAR%.zip" "!FOLDER!\*.*"
        endlocal
    )
)

endlocal
exit /B

I preceded the (potentionally dangerous) 7z command line by ECHO, just for safety purposes.



来源:https://stackoverflow.com/questions/57613888/how-to-compress-all-files-with-exception-of-newest-file-in-each-subfolder-of-a-f

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!