1

I have the following file and folder structure (using real names):

Carabidae/Pterostichinae/FolderNameXXX/dor/StackXXX/files.tif

My problem is that I need to get one specific file, PM*.*, from the StackXXX folders into their respective /dor parent folders. The StackXXX folder can then be deleted.

There are hundreds of FolderName. Ideally I would like a batch file I can run from the Carabidae folder.

This needs to be a batch file because there will be new FolderNames added constantly.

After a lot of searching, I found a semi-working solution from this StackOverflow answer:

for /f "delims==" %%i in ('dir /a:d /b') do for /f "delims==" %%f in ('dir %%i /a:d /b') do (move "%%i\%%f\PM*.*" "%%i"&&rd "%%i\%%f" /s /q)

It moves the file and deletes the folder, just as I want. But the problem is that it only works when run from a FolderName folder, which defeats the time-saving purpose of the script. I don't know how to modify it to recurse into subfolders so I can run it from the top folder.

Thank you very much for any help!

trilobutt
  • 13
  • 3
  • `for /r` can help you... –  May 29 '17 at 08:07
  • I thought so too, but it didn't work with that line of code. I tried replacing both `for /f` and each one separately, didn't work any of the times... – trilobutt May 29 '17 at 08:23
  • Do you understand how `for /r` works? Please check https://ss64.com/nt/for_r.html for more information and methods of usage –  May 29 '17 at 08:27
  • You must use the standard Windows path separator `\ `instead of `/`, which is the switch indicator! otherwise, unexpected behaviour might occur... – aschipfl May 29 '17 at 09:05
  • Do *not* use `for /R` when you are modifying the directory tree you are enumerating, or you may receive errors; see [this thread](https://stackoverflow.com/q/31975093) for the reason why; `for /F` together with `dir /B [/S]` ensures that the directory (tree) is enumerated *before* any items become modified... – aschipfl May 29 '17 at 09:10
  • Is `XXX` significant? Must it match the `XXX` in both parts of the path? What happens if there more than one subdirectory of `dor` exists? Does the exercise need to be performed on all subdirectories directly under `Pterostichinae` ? – Magoo May 29 '17 at 09:12
  • Thanks for the link, I didn't know there was a reference page like that. Anyway, I now see why a simple replace doesn't work. Making progress here, but I don't know how to specify a move to the parent folder of each file. As it is, I am moving each file to the parent folder of the batch script :) – trilobutt May 29 '17 at 09:18
  • The code from scratch I have so far is: `for /r %%G in (PM*.*) do copy ".."`, which just moves the correct files to the parent folder of the script. If I can figure out the command to specify the parent folder of the file, it will be solved. @aschipfl, I can use /r to just move the files, and delete folders manually, it's not too big an issue. – trilobutt May 29 '17 at 09:27
  • @Magoo, FolderNameXXX indicated there are many subfolders, each with different names, no regex possible for them. StackXXX have 'Stack' in common, but with different strings of numbers instead of XXX. There can be other folders than dor (there is lat, gen). The lack of constancy is why I'm looking for a solution that works only with folder hierarchies, not with folder names and some sort of regular expression. – trilobutt May 29 '17 at 09:27
  • Why did you provide `files.tif` in your sample path? it seems not to be relevant for your question at all! Additionally, please tell us what should happen in case of collisions (file `PM*.*` already exists in the upper directory level)! – aschipfl May 29 '17 at 09:29
  • There are many files in Stack* folder, but the only one I need is the PM*.* file. For clarity, I am dealing with systematic macro photos made using stacking methods (combining 100 raw photos into one). I need to get the final stacked photo away from the raw photos, into the parent folder (where it is then automatically renamed and uploaded to the database). There is no way to save in parent folder with the stacking program. There cannot be a clash between two PM*.* files in the same directory (it would happen at an earlier step in the workflow and I would have handled it then). – trilobutt May 29 '17 at 09:42

2 Answers2

2
@ECHO OFF
SETLOCAL
SET "sourcedir=u:\Carabidae"
FOR /f "tokens=1*delims=" %%a IN (
 'dir /b /s /a-d "%sourcedir%\pm*.*" '
 ) DO IF EXIST "%%a" (
 FOR %%p IN ("%%~dpa..\.") DO IF /i "%%~nxp"=="dor" (
  ECHO %%a|FINDSTR /i "\\dor\\Stack" >NUL
  IF NOT ERRORLEVEL 1 (
   ECHO MOVE /y "%%~dpa\pm*.*" "%%~dpa..\"
   ECHO RD /s /q "%%~dpa"
  )
 )
)

GOTO :EOF

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

Find all of the pm*.* files, filenames to %%a

Ensure the parent directory is dor and ensure that \dor\stack\ is in the path. If so, move the file(s) and remove the directory.

The if exist gate ensure no hiccoughs if a target directory contains more than one pm*.* file.

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 delete the directories.

Add >nul at the end of the move command to suppress the move-report if required.

As usual, I'd suggest you test against a representative subtree first.

Magoo
  • 77,302
  • 8
  • 62
  • 84
  • Sorry for the late reply, finished work before I could test it fully. It worked perfectly, and is flexible enough to account for any inconsistencies in folder names. Thank you very much! – trilobutt May 30 '17 at 06:52
1

Here is a possible solution, given that only the XXX parts in your path sample are variable:

rem // Enumerate `FolderName*` directories:
for /D %%R in ("Carabidae\Pterostichinae\FolderName*") do (
    rem // Enumerate `Stack*` sub-directories within `dor` sub-directories:
    for /F "delims= eol=|" %%D in ('dir /B /A:D "%%~R\dor\Stack*"') do (
        rem // Check for `PM*.*` files in `Stack*` sub-directories:
        (
            rem // Enumerate `PM*.*` files:
            for /F "delims= eol=|" %%F in ('dir /B /A:-D "%%~R\dor\%%D\PM*.*"') do (
                rem /* Move `PM*.*` file one directory level up, overwriting
                rem    an already existing file, if applicable: */
                ECHO move /Y "%%~R\dor\%%D\%%F" "%%~R\dor\%%F"
            )
        ) && (
            rem /* Remove `Stack*` sub-directory after file movement;
            rem    this is skipped if no `PM*.*` files have been found in the `Stack*`
            rem    sub-directory, so when the `for /F %%F` loop did never iterate: */
            ECHO rd /S /Q "%%~R\dor\%%D"
        )
    )
)

After having successfully tested whether or not the correct items are returned, remove the upper-case ECHO commands to actually move PM*.* files and remove Stack* directories!

aschipfl
  • 33,626
  • 12
  • 54
  • 99