How to remove subfolder and keep files

This is a kind of collapse-up request.

I have a large collection of ebooks (or music) in folders by author, with none or many books in each folder. However, there are a variable number of subfolders under each of these primary folders, each subfolder contains a further 1-3 files (or may be empty).
What I would like to do is: a) move all the files in subfolders up one level to the parent folder, then delete the newly emptied SUB-folder. The final format would just be the original collection of folders, but no subfolders left (and no files deleted!).

To make it more complex, there just might be a further sub-sub-folder that I have missed. I obviously I don't want to lose its contents either, but move those files also to the parent.. Essentially I want to collapse a tree upwards, keeping the files / killing the folders.

I wonder if anyone has any ideas on a button I could create for this? This problem frequently arises for me, and its very tedious and hard on the fingers to do such a repetitive task manually.

I wouldn't make a button for this, I'd simply put the lister in flat view then drag and drop the files up to whichever parent folder you wanted.

Have a look in this thread:

[url]Moving files around via context menus]

The code you´re looking for might be this one:

@dirsonly @nofilenamequoting Copy MOVE FILE "{filepath$}\*" HERE Delete QUIET NORECYCLE

I´d strongly advise you to check it in some test folders first, because they contain a "dangerous"
Delete QUIET NORECYCLE, so your empty folders will be erased.

[quote="JohnZeman"]I wouldn't make a button for this, I'd simply put the lister in flat view then drag and drop the files up to whichever parent folder you wanted.[/quote] Thanks for the suggestion John. I have been doing this procedure up till now already and it works fine for one small tree at a time. The problem is that there are hundreds of folders containing subfolders! I have to select each set of files in each subfolder manually, and move the subfiles up a folder level manually for each one. It works, but man its hard on my wrist and fingers after a few minutes of repetitive mousing. This is precisely the procedure I am try to automate.

[quote="abr"]The code you´re looking for might be this one:

@dirsonly @nofilenamequoting Copy MOVE FILE "{filepath$}\*" HERE Delete QUIET NORECYCLE I´d strongly advise you to check it in some test folders first, because they contain a "dangerous"
Delete QUIET NORECYCLE, so your empty folders will be erased.[/quote] Thanks abr. I tried your command, and it partly works on a SINGLE folder (with subfolders) at a time, but only under certain conditions/circumstances, and does not work on multiple folders at once. its quite a mess in terms of what I would like to achieve.
I may not have been clear enough on what I need to achieve. I need to select a primary folder that contains in it (say) 10 folders each named after (say) one author (lets call these 10 the parent folders I want to keep). Each of the 10 parent folders I have selected has: a) a file or more in them and b) a subfolder with a file or more in that. When I select the first 10 parent folders (of authors) I would like the command button to: a) LEAVE the existing files in the parent folders alone and also leave those parent author folders alone, but b) take each subfolder, and move the files in them up one level and then delete that empty subfolder. The result is that the parent folder is retained, all subfolders are gone, and their former contents are in the parent folder now.

Start:
folder1: file1
.....subfolderA: file 2, file3
folder2: (there are no files here)
.....subfolderB: file 4, file5
etc

Result:
folder1: file1, file 2, file3
folder2: file 4, file5
etc

What I get with your command is all the subfolders moved up a level, but they are still the same subfolder names. So, if i had 10 folders with 1 subfolder in each, the result of this button is now up to 20 folders. ie the contents of the subfolders are not moved one level up, but the entire subfolder is moved. Secondly, all the files in the list of folders are moved up one level into a single folder. If the parent folder is empty at the start (no files, but has a subfolder with files), then this command makes the subfolder the parent and deletes the original parent (so thanks for the danger warning).

So its not working the way I need (yet!). I also need to select dozens of primary folders to run it on, or else i have to run it one folder at a time (too slow). I will check out the other thread, but some of them seem like batch files not button.

If I understand you correctly now Phil, I don't know of a way to do it totally within Opus other than drag and drop. You can go the other way and move files from a parent folder to the folder you're in, but if there's a way to move subfolder files to the folder you're in, I'm not aware of it.

So barring someone else with more smarts than I have coming up with a totally Opus solution, I'd use a batch file with an Opus button to do this. As always with something rather complex, test it thoroughly before you use it on anything important! It works for me on my Windows 7 machine, and it should work on other versions of Windows, but still, give it a good testing on test files and folders.

Ok, that said, here's the way I would do this. First use Notepad to create a new text file and paste the following into it:

[code]@echo off
setlocal enabledelayedexpansion
set SRC=%1
if "%2" neq "Opus" goto :oops1
if "%~1" equ "" goto :oops2

for /r %SRC% %%a in (*) do (
call :process "%%a" %SRC%
)
exit

:process
if "%~dp1" equ "%~2" goto :EOF
set X=%~1
move "%X%" "%~2"
goto :EOF

:oops1
echo This script must be run from Opus
pause
exit

:oops2
echo You must have folders selected
pause
exit[/code]

Save that file giving it the name you want. I named mine "D:\Mine\cmd\Move Subfolder Files to Parent Folder.cmd"

Next in Opus, create a new button and set it up like the screen shot below. Note you will need to change the "D:\Mine\cmd\Move Subfolder Files to Parent Folder.cmd" path in my Opus button to the path where you put your batch file, but that should do it.

You could do it using a rename script, but if using the batch file works then that seems just as good to me.

Wow John this works very well indeed. Thanks for such clear and very precise instructions also. I was not sure how you would run a cmd file from a button till now! As it is, this script works and is very very timesaving.

..but..
a) (a minor point) The newly empty subfolders are not deleted (and I need them to be gone). A workaround after running your script is to view the tree in View->Flatview->Mixed, sort by size, and then delete all the empty folders. This is reasonably easy. Can the script be modified to delete them? Or is that too risky? Its not worth a lot of trouble.

b) (a significant point) There are fewer files in my test runs after the script, than before. Its not a folder count, but a file count thats less. On inspection I found that before running the script some of the subfolders had contained a file with the same name as one already in the parent folder (but a different version/size) (see folder 3 example below). Your script overwrites the parent file with the subfolder file. What would be better is that when such a thing happens, the file moving up a level from the subfolder is renamed when there already exists a file with the same name, such as appending "_01", "_02" etc to the end of the filename (before the extension). If the preexisitng file is the same size, then it does not matter either way (overwrite OR rename the new).

Start:
folder1: file1
.....subfolderA: file2, file3
folder2: (there are no files here)
.....subfolderB: file4, file5
folder3: file6
.....subfolderB: file6, file7
etc

Result:
folder1: file1, file2, file3
folder2: file 4, file5
folder3: file6, file6_01, file7
etc

Thanks again, even what you have done so far is a great great help.

a) I would do that in a second unrelated operation. Maybe set the Opus button up so a left click moved the files and a right click deleted the empty folders.

b) I realized that after I posted the above script. As you noticed, the MOVE operation of it literally moves the files and overwrites any files in the parent folder that have the exact same name. Tomorrow I'll see if I can't tweak the script so it renames instead of overwriting (right now I've got a cold beer and a pizza calling my name). :smiley:

Thanks. You deserve it!

Here's the latest version Phil. The script should handle up to 1000 name clashes in each selected folder, if you need more than that, find 1000 in the script and make it a higher number. You also might want to add @nodeselect to your Opus button so the folders stay selected after the files have been moved.

[code]@echo off
setlocal enabledelayedexpansion
set SRC=%1
if "%2" neq "Opus" goto :oops1
if "%~1" equ "" goto :oops2

for /r %SRC% %%a in (*) do (
call :process "%%a" %SRC%
)
exit

:process
if "%~dp1" equ "%~2" goto :EOF

set X=%~1
rem IF THERE IS NO NAME CLASH, MOVE THE FILE
if not exist "%~2%~nx1" (
move "%X%" "%~2"
) else (
rem HOWEVER IF THERE IS A NAME CLASH...
for /l %%b in (1,1,1000) do (
if not exist "%~2%~n1_%%b%~x1" (
move "%X%" "%~2%~n1_%%b%~x1"
goto :EOF
)
)
)
goto :EOF

:oops1
echo This script must be run from Opus
pause
exit

:oops2
echo You must have folders selected
pause
exit[/code]

Next is a another button and script you can use after running the first one above. It should remove up to 5 levels of empty subfolders in your selected folders. If you need more than 5 levels of subfolders removed, change the 5 in (1,1,5) to a higher number. As before, you will need to edit the name and path in the Opus button so it matches the name and path of the script.

[code]@echo off
if not "%OS%"=="Windows_NT" exit
if {%1}=={} exit
if "%2" neq "Opus" exit

pushd %1

:: The next loop makes 5 passes to remove 5 levels of empty directories
:: If you need more than 5 passes, increase the 5 in (1,1,5)
:: to a higher number
for /L %%a IN (1,1,5) do (
for /f "delims=" %%a in ('dir /a:d/b/s ""') do (
dir /a:-d "%%a">NUL 2>NUL
if errorlevel 1 (
rd "%%a" 2>NUL
)
)
)
popd
exit[/code]

John I REALLY appreciate your generosity in helping me with this. I hope your tools help a wider audience also.

Your second script to remove empty folder works perfectly for me in my test runs. I am very pleased! Thanks.

Your first script is "almost" there, but misses a few files and subfolders. The problem took me quite a while to pin down (as I sure it took you time to write in the first place). Some subfolders were not emptied of any files at all, and some files were simply not touched, despite others in the same folder being moved up a level. The common thread is simple: "&". If the ampersand symbol & is present in the filename OR the folder name, the script ignores that file or folder. It does however carry on and do all the other non-& folders. If the folder has & in the title, then all the files in that folder are also skipped, even though they have no & within their filename. As I do not understand how this script works (not following the commands), I cant play around with it myself. Does this problem ring any bells? While I can workaround this particular issue, I am wondering whether there are other symbols it would choke on that I do not have in my test tree set.

I also note that the presence of the & in the folder name does NOT upset your empty folder cleaner script, only this file moving script. I tried it 4 levels deep and its ok for cleaning empty folders.

Apart from that point, it works well on the rest of the files, gently renaming duplicates with _1 or _2 at the end of the file name. I am very pleased and grateful for your efforts.

Unfortunately Phil, the & symbol has a special meaning in batch files so when an ampersand (&) is encountered in a file or folder name, the script fails for that item as you've noticed. The & can be escaped in some situations, however IMO it's not really practical in scripts like this one.

For this reason I never use the & symbol in any of my file or folder names.

If someone wanted to duplicate what this script does in a VB rename script, this limitation may not be an issue, but off the top of my head I'm not sure about that. However if it were me, I'd replace all the &s with the word "and" instead. If the files/folder names are generated by another program, you could create a simple Opus rename button to replace all &s with the word "and".

The ampersand is ignored in the delete empty folders script because the script doesn't check any file or folder names. It simply does a scan of each directory for files, and when it finds none, the directory is removed.

Thanks John. I also found the same problem with files/folders containing "!" So I guess its not all surprising, from what you said about batch files. Despite this rather small limitation, I just tried out the two scripts on a 14k library, with 6-8 folders deep and 14678 files. Working in batches of the largest folders first (no more than 5 folders deep), then all the rest later, it took me about 15 min to complete a task that would have taken me months and given my wrists RSI! This is a mammoth task and I really could not have completed it another way. I can't thank you enough!
This library was created by someone else (using the free software calibre), and had been carelessly put together, and way more than 256 characters deep in many folder trees. Hence the few & and ! scattered around in folder and file names. Like you, I have always avoided such characters in my file names, but I cant control other people.

The twin scripts will come in real handy for many similar repetitive tasks I encounter almost weekly. I'll report back on any other queries that may arise, but I really doubt there is more troubleshooting to perform, after the gigantic run i just did. But right now, I am supposed to be at work, so better fly (it may be afternoon for you over there, but its Monday morning here in Oz). I greatly appreciate your time, help and enthusiasm.

Filenames with & etc. in are not a problem for VBScript. It's only the DOS batch language (if it's fit to be called such a thing :slight_smile:) that has such silly problems.