1

Here is the way to delete all files in current folder except bat-files:

forfiles /c "cmd /c if @isdir equ FALSE if /i not @ext==\"bat\" del @file"

(I found it here).

As I discovered, if I change FALSE to false, it will not work. Why? It's my main question.

Also, side question. Is it correct, that the first code is equal to:

forfiles /c "cmd /c if @isdir==FALSE if /i not @ext==\"bat\" del @file"

?

john c. j.
  • 725
  • 5
  • 28
  • 81
  • Why are you using `FORFILES` when a standard `FOR` command would work just fine. The `FOR` command will only list files. – Squashman Dec 22 '17 at 20:45
  • @Squashman I'm not familiar with bat-scripts. The provided solution was copy-pasted from the link I have posted below it. Another solution from the same author (`for /f %%F in ('dir /b /a-d ^| findstr /vile ".sdb .sbk .log .bat"') do del "%%F"`) doesn't work for filenames with spaces. – john c. j. Dec 22 '17 at 20:48
  • 1
    It has nothing to do with the `forfiles` command and everything to do with the `if` statement. Check out `if /?`. – SomethingDark Dec 22 '17 at 20:48
  • Your `FOR /F` command does not work because you didn't bother to read the help file for the `FOR` command. It uses a space as one of the default delimiters to split up the output into multiple tokens. – Squashman Dec 22 '17 at 20:50
  • @SomethingDark it has everything to do with `FORFILES` as indicated by Mofi's answer. – Tzalumen Dec 22 '17 at 20:52
  • @Tzalumen - If you actually read Mofi's answer, you'd know that the problem comes from not using the `/I` flag of `if` to make the comparison case-insensitive. – SomethingDark Dec 22 '17 at 20:53
  • You need to tell the `FOR /F` command to not use any delimiters. `for /f "delims=" %%F in ('dir /b /a-d ^| findstr /vile ".sdb .sbk .log .bat"') do del "%%F"` – Squashman Dec 22 '17 at 20:56
  • Would like to let you know that using `FORFILES` will be much slower then using a `FOR` or `FOR /F` as the `FORFILES` command has to open a new environment with CMD.exe for each file it iterates. Hope you don't have a lot of files to process. – Squashman Dec 22 '17 at 20:59
  • @Squashman Thank you :) I will try to play with it more. – john c. j. Dec 22 '17 at 21:18
  • @Squashman Thank you again, now I have read the `FOR` help info. Are there any drawbacks of `"delims="`? – john c. j. Dec 22 '17 at 21:47
  • `"delims="` just means "don't split the string at all." It's useful for if your files have spaces in their names. – SomethingDark Dec 22 '17 at 22:20

2 Answers2

5

@isdir expands always to FALSE or TRUE in upper case.

if @isdir equ FALSE is a case-sensitive string comparison of FALSE or TRUE with FALSE using integer comparison operator EQU falling back to a string comparison because of neither string FALSE nor string TRUE can be converted successfully to an integer, see Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files for details.

For a case-insensitive string comparison use in the command line:

if /I @isdir == FALSE

And if @isdir==FALSE is better than if @isdir equ FALSE, but the behavior is the same.

Best is to use if @isdir == FALSE as this is 100% correct syntax.


IF command syntax for string comparison on equality:

IF FirstStringToCompare == SecondStringToCompare Command

or for strings containing a space or &()[]{}<>|^=;!'+,`~

IF "first string to compare" == "second string to compare" "command to execute"

The command is IF separated from first argument string with a space character which is either the string FALSE or the string TRUE in this case. The first string to compare is separated from second argument with a space with is the equal operator ==. After one more space the third argument is specified which is the second string to compare. The last command separated again with a space from third argument is the command to execute on string equality.

The spaces around operator == are often omitted although actually required to separate the first from second and second from third argument. But Windows command interpreter recognizes the missing spaces around operator == and add them automatically as it can be seen on writing into a batch file just the two lines

if FALSE==FALSE echo It is FALSE.
if   TRUE   ==   FALSE   echo It is FALSE.

and run this batch file in a command prompt window resulting in output:

if FALSE == FALSE echo It is FALSE.
It is FALSE.
if TRUE == FALSE echo It is FALSE.

The command lines really executed after preprocessing by Windows command interpreter have one space between each argument.

The help for command IF output on running in a command prompt window if /? shows the string comparison syntax as:

IF [NOT] string1==string2 command

So it can be supposed that the space left and right of == are not really required as long as the strings to compare do not contain itself an equal sign in which case it is necessary to enclose both strings to compare in double quotes.

Mofi
  • 46,139
  • 17
  • 80
  • 143
  • Solid. My .02$, @john c. j., this site is your friend https://ss64.com/nt/forfiles.html (relevant command linked) – Tzalumen Dec 22 '17 at 20:55
  • @Mofi Thank you. Before posting this question at Stack Overflow, I briefly looked [examples, provided on MS Technet](https://technet.microsoft.com/en-us/library/cc753551(v=ws.11).aspx). Here is one of them: `forfiles /p c:\ /s /m *.* /c "cmd /c if @isdir==true echo @file is a directory"`. As you see, it use lower-case, and there is case-insensitive switch. So, Microsoft's example is incorrect? – john c. j. Dec 22 '17 at 20:56
  • @john-c-j Yes, Microsoft's given code example for the `@isdir` is incorrect. I wondered if they might have made a mistake, so I tested that. The `@isdir==true` given by Microsoft always evaluates to false, but using `@isdir==TRUE` works as expected. – Tzalumen Dec 22 '17 at 21:06
  • @Mofi I see, you updated an answer. It's nice to discover new things every day. By the way, do you agree with Squashman that it's better to use `for /f`, like this: `for /f "delims=" %%F in ('dir /b /a-d ^| findstr /vile ".bat"') do del "%%F"` instead of `forfiles` for this task? – john c. j. Dec 23 '17 at 15:16
  • @johnc.j. Yes, I agree with Squashman. The __FOR__ command line as posted by Squashman is for this task definitely better because of being much faster. The command __FOR__ has to run only once in a separate command process in background the command line with __DIR__ and __FINDSTR__ to get a list of files not including *.bat files and then just run in current command process command __DEL__. __FORFILES__ needs to run a separate command process with two __IF__ and __DEL__ for each directory and each file which is definitely slower. – Mofi Dec 23 '17 at 18:23
  • @Mofi Hallo! Yes, I see, the page is now correct. Thank you very much for this improvement in Microsoft docs. I will remove my comment as well. – john c. j. Nov 21 '18 at 21:03
2

Answer to your first question can be found here https://technet.microsoft.com/en-us/library/cc753551(v=ws.11).aspx where it states ... "@ISDIR Evaluates to TRUE if a file type is a directory. Otherwise, this variable evaluates to FALSE."

RGuggisberg
  • 4,630
  • 2
  • 18
  • 27
  • As I understand, I must use upper case. Ironically, the same page provides (incorrect?) example with lower case: `forfiles /p c:\ /s /m *.* /c "cmd /c if @isdir==true echo @file is a directory"` – john c. j. Dec 22 '17 at 20:51