1

First of all, similar questions have been answered in past but not exactly the one I have. In some other solutions, hiding folders/files and changing attributes were suggested and I do not want this, unless there is no simpler way available. Also, I have tried the solution suggested here (and couple of others): MS-DOS command to delete all files except one.

But did not work for my need due to two reasons:

  1. This also deleted the file, I did not want to.
  2. This did not delete the sub-folders but only the files.

So, I have folder c:/users/data and in there, I have 5 folders and 6 files I want to delete everything except one which is web.config and to do that I run the batch file like this:

@echo off
for %%j in (C:\Users\data\*) do if not %%j == Web.config del %%j
pause

But when I run the batch file, this deletes all the files including web.config and also, does not delete any of the sub-folders and if I use the /d switch then it only deletes folders not files. How can I delete both files and folders?

Community
  • 1
  • 1
Viki2016
  • 55
  • 2
  • 9
  • check the output of `for %%j in (C:\Users\data) do echo %%j` and verify if `%%j`really is what you want (I doubt...) [reference](http://stackoverflow.com/a/39146854/2152082) – Stephan Aug 26 '16 at 06:51
  • @Stephan, it was a typo, I have edited the question for directory mistake but problem is, this `for %%j in (C:\Users\data\*) do echo %%j` outputs only the files not everything and if I say something like `for /d %%j in (C:\Users\data\*) do echo %%j` then outputs only the folders whereas, I want to see both files and folders.. – Viki2016 Aug 26 '16 at 07:14
  • check the output of `for %%j in (C:\Users\data\*) do echo %%j` and re-think whether `if not C:\Users\data\web.config == web.config` could work... – Stephan Aug 26 '16 at 07:20
  • 1
    What's wrong with copying the file elsewhere, delete everything and put the file back? At least your batch file will be much more readable and hence maintainable. – Dominique Aug 26 '16 at 07:24
  • @Dominique, only one problem, there are more then 50 folders from where I want to delete everything but web.config and then from another folder I will be copying into these 50 folders therefore, I think (mvho), another copying command will add bit of a time issue. However, please suggest something and I will be more than happy to try.. – Viki2016 Aug 26 '16 at 07:34
  • In case you have Cygwin or another UNIX emulator, you could use `du -k | awk '{print $2}' | grep -v ""` – Dominique Aug 26 '16 at 07:43
  • @Stephan, I believe this is what you meant `for %%j in (C:\Users\data\*) do if not %%j == C:\Users\date\web.config del %%j` now it deletes all files but web.config however, another issue is still there and this does not delete the sub folders.. – Viki2016 Aug 26 '16 at 08:04
  • you can use `do if not %%~nxj == web.config del %%j`. To remove folders, use [rd](http://ss64.com/nt/rd.html) – Stephan Aug 26 '16 at 08:11
  • Is the file `web.config` always located in the root `C:\Users\data` immediately, or could it also be located in one of its sub-folders? what to do in such cases -- exclude it from deletion also? – aschipfl Aug 26 '16 at 11:21

3 Answers3

3

Here is the way I would do it:

pushd "C:\Users\data" || exit /B 1
for /D %%D in ("*") do (
    rd /S /Q "%%~D"
)
for %%F in ("*") do (
    if /I not "%%~nxF"=="web.config" del "%%~F"
)
popd

The basic code is taken from my answer to the question Deleting Folder Contents but not the folder but with the del command replaced by a second for loop that walks through all files and deletes only those not named web.config.

Note that this approach does not touch the original parent directory, neither does it touch the original file web.config. The great advantage of this fact is that no attributes are going to be lost (for instance, creation date and owner).

Explanation

  • change to root directory by pushd; in case of failure, skip the rest of the script;
  • iterate through all the immediate sub-folders of the root by a for /D loop and delete them recursively by rd /S with all their contents;
  • iterate through the files located in the root by a standard for loop; use the ~nx modifier of the loop variable to expand base name (n) and extension (x) of each file, compare it with the given file name (if) in a case-insensitive manner (/I) and delete the file by del only in case it does not match (not);
  • restore former working directory by popd finally;

The main problems in your code are:

  • that you compare more that the pure file name with the prefedined name, so there is not going to be found any match.
  • you needed to use case-insensitive comparison, because Windows does not care about the case of file names for searching.
  • you did not put quotation marks around the comparison expressions, so you are likely going to receive syntax error messages, depending on what special characters occur in the file names.
  • that you are using the del command only which just deletes files; to remove directories, you needed to use rd also.
Community
  • 1
  • 1
aschipfl
  • 33,626
  • 12
  • 54
  • 99
  • 1
    can you please explain how this script works, this would be very helpful for me... – Viki2016 Aug 26 '16 at 10:37
  • Aren't you deleting all the folders and their contents here, even before you get a chance to check if they contain a file you don't want to delete? – Klitos Kyriacou Aug 26 '16 at 11:06
  • @KlitosKyriacou, as far as I understood, the file to exclude from deletion is located in the root folder `C:\Users\data`, so this works; if a file `web.config` is in one of its sub-folders, then you are right, it will be deleted; I hope I did not misinterpret the question... – aschipfl Aug 26 '16 at 11:11
  • I implemented a brief explanation -- see my [edit](http://stackoverflow.com/revisions/39163035/3)... – aschipfl Aug 26 '16 at 11:19
  • @aschipfl, the web.config file will always be here `c:\user\data\web.config` – Viki2016 Aug 26 '16 at 11:35
  • @aschipfl, what does ~ mean here `if /I not "%%~nxF"=="web.config" del "%%~F"`. Can you explain this for me.. – Viki2016 Aug 26 '16 at 13:16
  • The `~` tells to expand the variable with potential surrounding quotation marks removed; so `%%F` could contain quotes, `%%~F` does not; hence `"%%~F"` always contains quotes (note that `"%%F"` could contain too much quotes unintentionally). Type `for /?` into a new command prompt window and read the help -- you can find the `~` also there... – aschipfl Aug 26 '16 at 13:30
1

I'm not sure where the web.config file is stored or if there is more than one, so ...

Only one web.config file

Just lock the file (redirect the file as input) and remove anything else

@echo off
    setlocal enableextensions disabledelayedexpansion

    pushd "c:\users\data" && >nul 2>nul (
        <"web.config" rmdir . /s /q
        popd
    )

The code will

  1. (pushd) Change to the target folder (we need to be sure this will remove information only from the intended place) setting it as the current active directory and locking it (we can not remove the current active directory). If the command can change to the folder then

  2. (rmdir) Redirect the web.config as input to the rmdir command. This will lock the file so it can not be deleted until the command ends. The rmdir . /s /q remove anything not locked inside (and below) the current active directory

  3. (popd) Cancel the pushd command restoring the previous active directory

Several web.config files in multiple folders

Following the approach (copy, clean, restore) pointed by @Dominique

@echo off
    setlocal enableextensions disabledelayedexpansion

    pushd "c:\users\data" && >nul 2>nul (
        for %%t in ("%temp%\%~n0_%random%%random%%random%.tmp") do (
            robocopy . "%%~ft" web.config /s
            robocopy "%%~ft" . /mir
            rmdir "%%~ft" /s /q
        ) 
        popd
    )

The code will

  1. (pushd) Change to the target folder (we need to be sure this will remove information only from the intended place). If the command can change to the folder then

  2. (for) Prepare a reference (a random name) to a temporary folder to use

  3. (robocopy) Copy only the web.config files (and their folder hierarchy) from the source folder to the temporary folder

  4. (robocopy) Mirror the temporary folder to the source folder. This will remove any file/folder not included in the temporary copy

  5. (rmdir) Remove the temporary folder

  6. (popd) Cancel the pushd command restoring the previous active directory

Once the web.config files are saved, as the files in the source will match those in the temporay folder, they will not be copied back with the second robocopy call, but any file/folder in source that is not present in the temporary folder will be removed to mirror the structure in the temporary folder.

MC ND
  • 69,615
  • 8
  • 84
  • 126
0

I also managed to do it, very similar to @aschipfl

For /D %%k in (C:\Users\data) do (For /d %%m in ("%%k\*") do rmdir /s /q "%%m"
For %%m in ("%%k\*") do if not %%m == %%k\Web.config del /q "%%m")
Viki2016
  • 55
  • 2
  • 9
  • Hm... to me this answer looks like nothing but a copy of mine but with an additional useless `for /D %%k` loop and some syntax flaws... – aschipfl Aug 26 '16 at 14:52
  • @aschipfl, That's why I said, very similar to yours..and I did not mark mine one as answer but yours. In terms of syntax flaws, as I mentioned in my first question that I am not an expert but learning and while going through different solutions, I mixed them including yours... – Viki2016 Aug 30 '16 at 12:05
  • What is the purpose of the outer-most `for /D %%k` loop? you know it will always iterate once only, returning `C:\Users\data` in `%%k` (even in case the directory does not exist); I recommend to change the `if` query to `if /I not "%%m"=="%%k\Web.config"` (quoting avoids trouble with some special characters, `/I` defines case-insensitive comparison)... – aschipfl Aug 30 '16 at 14:17
  • @aschipfl, ya, I know it will only iterate once, I only need to select everything in `C:\Users\data` and then first, I will remove the directories and then all the files except `web.config`. Yes, you are right and I will surely replace the `if` query to `if /I not "%%m"=="%%k\Web.config"`. Another thing, in your proposed solution, will I have not the problem as you mentioned about **my query will loop even in case the directory does not exist** – Viki2016 Aug 30 '16 at 14:29
  • `for /D %%k in (C:\Users\data) do` will not return the content of `C:\Users\data`, it iterates once, only returning `C:\Users\data` itself, without even accessing the file system (`for` does that *only* in case a wild-card `*` or `?` is provided); so replacing every `%%k` in your code by `C:\Users\data` behaves exactly the same. In my solution, `|| exit /B 1` lets the script terminate in case `pushd` fails, meaning that the path does not exist... – aschipfl Aug 30 '16 at 18:23
  • @aschipfl, many thanks for the detailed information, so `For /D %%k in (C:\Users\data\*) do` will iterate more than once then.. – Viki2016 Aug 31 '16 at 07:10
  • Yes, it would, but there is already the loop `for /D %%m`, which (when `%%k` is replaced by `C:\Users\data`) already does exactly the same iteration... – aschipfl Aug 31 '16 at 08:59