1

I want to delete all the files on a given folder after the extraction is successfully completed (errorlevel 0). There are several folders and inside them are several 7z splitted files, I want to delete all the 7z files from folder 1 only if the extraction went successfully, then proceed to extract file from folder 2 and then (again) delete all the 7z files inside that folder if the extraction completed successfully, and so on.

I currently have something like this:

FOR /R E:\tmp\ %%g IN (*.7z.*) DO 7z x "%%~dpng.001" -o"%%~dpg"
if %errorlevel% EQU 0 del "%%g"

So only after the whole loop is completed it starts to perform the deletion which I don't want to be done like that. I want the deletion to be triggered on every extraction successfully done.

If I set the batch like this:

FOR /R E:\tmp\ %%g IN (*.7z.*) DO 7z x "%%~dpng.001" -o"%%~dpg" & if %errorlevel% EQU 0 del "%%g"

I got somewhat what I want because the batch starts to perform the deletion after every extraction but it also does that wrong. If I have a folder inside E:\tmp\ called "Test" and inside there are files Test.7z.001 to Test.7z.003 the batch starts to extract Test.7z.001 and then proceeds to delete only Test.7z.001, then it starts to try to extract the file Test.7z.002 and, as it fails, it proceeds to delete only the file Test.7z.002 which it shouldn't because it has failed extracting which also tells me that the - if - isn't set properly, the same happens with the file Test.7z.003.

Well, that was already visible from the cmd window as I get something like this when the batch is starting:

FOR /R E:\tmp\ %g IN (*.7z.*) DO 7z x "%~dpng.001" -o"%~dpg"   & if 0 EQU 0 del "%g"
7z x "E:\tmp\Test 3\test3.7z.001" -o"E:\tmp\Test 3\"   & if 0 EQU 0 del "E:\tmp\Test 3\test3.7z.001"

From which it already implied an errorlevel of 0 without waiting for the extraction to be even started so no matter what it will execute the deletion. I guess it grabs the errorlevel from the result of the execution of the batch not the 7z action. I don't know much about batch, only basics and some things that I learned by necessity, batch loops are new to me. Sorry if my English isn't good, also I didn't know how to phrase the title.

aschipfl
  • 33,626
  • 12
  • 54
  • 99
churchill
  • 109
  • 6

2 Answers2

2

Variables are expanded at execution time. So %errorlevel% is already resolved to the last previous executed command. So when you have everything on one line it really isn't working the way you think it is. Also remember you are using two different examples. One is from a batch file and the other is from the command line so things may act slightly differently when you do that.

You should consider using parentheses regardless of doing it from the command prompt or in a batch file. Using the IF ERRORLEVEL syntax will also help you with this.

So you have a few options.

From a batch file.

 FOR /R E:\tmp\ %%g IN (*.7z.*) DO (
      7z x "%%~dpng.001" -o"%%~dpg"
      if not errorlevel 1 del "%%g"
 )

You could also use conditional execution in a batch file all on one line. In this instance using a double ampersand will say if the last command was successful then execute the next command. Again use parentheses to group the commands together.

 FOR /R E:\tmp\ %%g IN (*.7z.*) DO (7z x "%%~dpng.001" -o"%%~dpg" && del "%%g")
Squashman
  • 13,649
  • 5
  • 27
  • 36
  • Thank you, didn't occurred to me to encapsulate it, is possible to set two types of archives, like (*.7z.*, *.rar) or something alike? – churchill Nov 21 '19 at 09:20
  • After some testing with multi part files, it only deletes the first one (*.7z.001) and the others are left there, is there a way to force/trigger the deletion of the other files too? I'll explain myself better, after executing the batch it deletes the first file, then it tries to extract the second and as it fails ('cause 001 is gone) it doesn't delete that one, the same with the other parts, its happening the same as what it was happening before. – churchill Nov 21 '19 at 23:06
  • @churchill, I read the 7zip documentation after realizing you were listing all the multipart files but only using the 001 for extraction. You do not need to use the FOR command to iterate all the multipart files. You only need the FOR command to grab the .001 file. 7zip can naturally detect that it is a multipart file and will extract all of them. But there is a `-t` switch you can use to specify that the .001 file is a split file. The `FOR` clause should just be `(*.7z.001)`. Then you can just use `%%g` with the `7z` command and `%%~dpng*` with the `DEL` command. – Squashman Nov 22 '19 at 00:22
2

Squashman already showed you (at least in my opinion) the preferred way (using &&) to accomplish what you want in his answer.

Anyway, to overcome the issue with %ErrorLevel% he explained you could use delayed variable expansion, like this:

for /R "E:\tmp" %%g in (*.7z.*) do (
    7z x "%%~dpng.001" -o"%%~dpg"
    setlocal EnableDelayedExpansion
    if !ErrorLevel! equ 0 (
        endlocal & del "%%g"
    ) else endlocal
)

I toggled delayed expansion within the loop body in order to avoid trouble with %%g containing characters ! or ^ that are consumed by delayed expansion.


To force the order of files to *.7z.001, *.7z.002, *.7z.003, independent on the file system of your drive (e. g., NTFS or FAT), you should change the for /R loop to this:

for /F "delims=" %%g in ('dir /S /B /A:-D /O:NE *.7z.*') do (
    rem // The loop body is not affected hereby...
)

Since you seem to deal with multi-volume archives, it should be sufficient to extract *.7z.001 (7z.exe should recognise that there are multiple parts and extract everything automatically), and then you could delete all respective parts in case of success:

for /F "delims=" %%g in ('dir /S /B /A:-D /O:NE *.7z.001') do (
    7z x "%%~fg" -o"%%~dpg."
    setlocal EnableDelayedExpansion
    if !ErrorLevel! equ 0 (
        endlocal & del "%%~dpng.*"
    ) else endlocal
)
aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • Sorry, but I disagree that "using `&&` is the _preferred way_ to accomplish this". IMHO using `&&` this way is cryptic and may lead to errors difficult to find. A simple `if` command is clearer... – Aacini Nov 21 '19 at 13:12
  • Well, @Aacini, this is a matter of tase I think; I personally prefer [`&&`/`||`](https://ss64.com/nt/syntax-redirection.html) over [`if`](https://ss64.com/nt/if.html) because: 1. `&&`/`||` is more compact; 2. `if [not] errorlevel 1` is ambiguous for a lot of people (many think it means `[not] equal to`); 3. `if` together with variable [`%ErrorLevel%`](https://ss64.com/nt/errorlevel.html) requires delayed expansion (`!ErrorLevel!`) to be used within a block of code like a loop; 4. there are [commands that do not set `ErrorLevel` properly](https://stackoverflow.com/q/11137702)... – aschipfl Nov 21 '19 at 15:18
  • Yes, this is a matter of taste, so it is the preferred way _for you_, not for all (as you implied in your answer)... – Aacini Nov 21 '19 at 15:36
  • Tried your code and is happening the same as with the other. The batch is deleting the file Test1.7z.001 after the successful extraction and then it tries again to extract the file Test1.7z.001 but if fails because it's already deleted so instead of ending (because errorlevel isn't 0) the action it continues to delete the file Test1.7z.002, and so on. I don't know if this was made on purpose since file 001 being gone means that the first action was completed which also implies that the extraction was successful, otherwise 001 would still be there and its deletion wouldn't have been performed. – churchill Nov 21 '19 at 23:23
  • Well, you've got multi-volume archives, right? so you should change the pattern `*.7z.*` to `*.7z.001`, so you begin to extract at the first part (hopefully; read the documentation of 7-Zip about such split archives); then when successful, do `del "%%~ng.*"` to delete all parts then... – aschipfl Nov 22 '19 at 00:57