0

I want to make a script that will iterate over all the folders in the current folder, then if a folder (that we iterate over) has only a single file or directory, to move that file or directory up one level. (And if possible to delete the now empty folder)

This is what I got so far:

for /d %s in (.\*) do (
@echo %s

set cnt=0
for %A in (%s) do set /a cnt+=1
echo File count = %cnt%

@echo %cnt //don't do anything
@echo %a   //don't do anything

if (cnt leq 1) (
move .\*.* ..
)
)

But it doesn't work and I have no idea why...

I took code from:

count script from: https://stackoverflow.com/a/11005300/4279201

Iterate over subdirs of current dir: Iterate all files in a directory using a 'for' loop

move: https://superuser.com/a/180578/451485

Community
  • 1
  • 1
shinzou
  • 5,850
  • 10
  • 60
  • 124

1 Answers1

1
@ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
:: First, create a list of subdirectorynames; iterate using `%%a`
FOR /f "delims=" %%a IN (
  'dir /b /ad "%sourcedir%\*" '
  ) DO (
 REM clear initial flags for each dir
 SET "flag1="
 SET "flag2="
 REM Now read the subdirectory. set flag1 for first file, flag2 for second or later
 FOR /f %%g IN (
  'dir /b /a-d "%sourcedir%\%%a\*" 2^>nul'
  ) DO IF DEFINED flag1 (SET flag2=y) ELSE (SET flag1=y)
 REM if neither flag set, directory is empty
 REM if both are set, dir has 2 or more files
 REM so - if flag1 but not flag2 is set then exactly 1 file.
 IF DEFINED flag1 IF NOT DEFINED flag2 ECHO(MOVE "%sourcedir%\%%a\*" "%sourcedir%\"
 REM if flag2 is not set, subdirectory is now empty
 IF NOT DEFINED flag2 ECHO(rd "%sourcedir%\%%a"
)

GOTO :EOF

You would need to change the setting of sourcedir to suit your circumstances.

The required MOVE commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(MOVE to MOVE to actually move the files. Append >nul to suppress report messages (eg. 1 file moved)

The required RD commands are merely ECHOed for testing purposes. After you've verified that the commands are correct, change ECHO(RD to RD to actually create the directories.

I'd suggest you target the batch on a tree that contains three subdirectories containing 0,1 and 2 files for testing.

Yur batch fails for a number of reasons.

  1. The metavariable (loop-control variable) in a batch file requires a double % in every reference
  2. environment variables are referenced by %var%, not %var.
  3. within a block statement (a parenthesised series of statements), %var% will refer to the value of var at the time the block is initially encountered, not as the variable changes within the loop. This is the delayed expansion problem - well-documented here.

Note that this batch does not check whether a candidate to be moved already exists in the destination directory. If it does, then the move and rd statements will generate an error report and the file and directory will remain as-is.

NB: do not change any rem line to the :: form as :: is in fact a broken label which terminates a block (ie. will cause problems)


Edit - revision

@ECHO Off
SETLOCAL
SET "sourcedir=U:\sourcedir"
:: First, create a list of subdirectorynames; iterate using `%%a`
FOR /f "delims=" %%a IN (
  'dir /b /ad "%sourcedir%\*" '
  ) DO (
 REM clear initial flags for each dir
 ECHO %%a
 SET "subdir=%%a"
 SET "flag1="
 SET "flag2="
 REM Now read the subdirectory. set flag1 for first file, flag2 for second or later
 FOR /f "delims=" %%g IN (
  'dir /b "%sourcedir%\%%a\*" 2^>nul'
  ) DO SET "name=%%g"&IF DEFINED flag1 (SET flag2=y) ELSE (SET flag1=y)
 REM if neither flag set, directory is empty
 REM if both are set, dir has 2 or more files/dirs
 REM so - if flag1 but not flag2 is set then exactly 1 file/dir
 IF DEFINED flag1 IF NOT DEFINED flag2 CALL :moveit
 REM if flag2 is not set, subdirectory is now empty
 IF NOT DEFINED flag2 rd "%sourcedir%\%%a"
)

GOTO :EOF
:moveit
REM NAME may be a file or a directory - "%sourcedir%\%%a\%NAME%\.." exists if directory
IF NOT EXIST "%sourcedir%\%subdir%\%NAME%\.." MOVE "%sourcedir%\%subdir%\*" "%sourcedir%\"
IF EXIST "%sourcedir%\%subdir%\%NAME%\.." IF NOT EXIST "%sourcedir%\%name%" MOVE "%sourcedir%\%subdir%\%NAME%" "%sourcedir%\"
GOTO :EOF

Caution! The above batch does NOT use ECHO( hence it will attempt to
move or delete files or directories. Use only on test subtree!

This minor revision moves single-directories as well as single-files up within the directories on the level below the target.

It displays sufficient information to infer the source of error messages if it can't move or delete as directed.

Essentially, it's the same as the original, exceot that a subroutine is called to make the changes. The subroutine uses name for the directoryname it hopes to move and subdir for the subdirectory being processed.

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • I changed the `U:\sourcedir` to `%~dp0` or `%cd%`, even to `c:\a` and made a folder there with some tests but but they don't do what they're supposed to... – shinzou Jan 11 '16 at 19:52
  • Regrettably, I cannot see your screen, so you have to be explicit about what it did. I can't read your mind about what you expect the batch to do. – Magoo Jan 11 '16 at 20:11
  • Here's a gif to solve that problem: http://i.imgur.com/TDZznfF.gif `new folder` has one file and it doesn't move to `c:\a`, nor does the single folder `asdf` from `new folder 2`: – shinzou Jan 11 '16 at 20:20
  • Try inserting a `PAUSE` line before the `goto :eof`. That will show the results. By running using point-click-and-giggle, the batch closes on termination without giving you an opportunity to see the results. – Magoo Jan 11 '16 at 20:27
  • Oh yeah now I see the commands, I should've known to use that, anyway, I removed the `echo(*` as you said, and it works for single files in subfolders but it doesn't move a single folder from a subfolder, i.e: http://i.imgur.com/SYdOf8k.gif it doesn't move the folder `asdf` back to its `c:\a`. – shinzou Jan 11 '16 at 20:43
  • I tried to change `'dir /b /a-d "%sourcedir%\%%a\*" 2^>nul'` to `'dir /b /a ...` (`-d` removed) but that didn't work.. – shinzou Jan 11 '16 at 20:44
  • I see you edited it, wow I can't believe it's so complicated to move a directory, I don't think I understand the logic behind `movieit` (move if not exist and if exist if not exist?) but it works! Than you very much! :) – shinzou Jan 11 '16 at 22:30
  • I don't want to bother you any more but if you can/want, please explain `moveit`. – shinzou Jan 11 '16 at 22:31
  • `%%a` in the main routine refers to the subdirectory. It is recorded as `subdir`. Similary, `%%g` is the name of an entry in the subdirectory, and that is recorded in `name`. We are dealing with the situation where there is exactly one `name` in `subdirectory`, so the fact that `name` is the last`name` in the subdirectory (according to the `dir/b` list) is not relevant - it's the only name (controlled by the flags.) Now if in the subroutine, `...\subdir\name\..` exists, then `name` must be a subdirectory; it will not exist if `name` is a file. – Magoo Jan 11 '16 at 22:58
  • The if exist/if not exist is checking for a subdirectory-to-be-moved called "abc" where the destination already contains "abc". If that is the case, then the `move` is not attempted. – Magoo Jan 11 '16 at 23:00