3

I have a script that extracts all files from all sub-directories and deletes the empty sub-directories afterwards, the part that extracts reads:

for /r %%a in (*.*) do move "%%a" "%~dp0"

Is there a way to do this with the exception of sub-directories named "_Unsorted"? I know xcopy has an /exclude option, so something like

for /r %%a in (*.*) do xcopy "%%a" "%~dp0" /exclude "\_Unsorted\"

would almost work, but I'm not sure how to delete the original after it's copied to essentially have the same result as move

Insarov
  • 971
  • 1
  • 10
  • 15

3 Answers3

3

Can you use robocopy?

robocopy from\path to\path *.* /mov /e /xd _Unsorted

/mov: move rather than copy (delete the source after copying)

/e: recursive (including empty subdirectories)

/xd _Unsorted: exclude directories named _Unsorted

Nate Hekman
  • 6,507
  • 27
  • 30
  • Hopefully, the OP uses a Windows version that has `robocopy`, although this powerful tool is worth mentioning either way. – Andriy M Mar 01 '13 at 22:44
1

Some batch-only options:

  1. Add a filter into the loop body:

    for /r %%a in (*.*) do (
      (echo %%~dpa | find /i "\_Unsorted\" 1>nul) || move "%%a" "%~dp0"
    )
    

    Alternatively:

    for /r %%a in (*.*) do (
      (echo %%~dpa | find /i /v "\_Unsorted\" 1>nul) && move "%%a" "%~dp0"
    )
    

    In both versions, the find command is used to match the file's path against the substring \_Unsorted\. In the first version, find returns success if there is a match and fail otherwise. The move command is called only in case of fail, which is the effect of the || operator`.

    In the second version, the /v switch reverses the result of find and success now means no match. Accordingly, the && operator is used to call move in case of success.

  2. Apply the filter to the file list, so that the loop never iterates over _Unsorted entries.

    for /f "delims=" %%a in (
      'dir /s /b ^| find /i /v "\_Unsorted\"'
    ) do move "%%a" "%~dp0"
    

    This is a more essential change to the original script than the previous option, as this replaces the for /r loop with a for /f one.

    Basically, a for /f loop is used to read/parse a piece of text, a text file or a command's output. In this case, the dir command provides a complete list of files in the current directory's tree and the find command filters out those containing \_Unsorted\ in their paths. The for /f loop reads the list after it's been filtered down by find, which means it never hits files stored in _Unsorted (sub)folders.

Andriy M
  • 76,112
  • 17
  • 94
  • 154
  • Looks promising, but they don't seem to work. The first two options extract the files from '\_Unsorted\' anyways and the latter option doesn't run. Any idea? – Insarov Mar 05 '13 at 16:25
  • There were mistakes in all of them (the facepalm kind ones). Please take a look now. – Andriy M Mar 05 '13 at 17:53
  • They work perfectly, thanks. Are any of these options inherently better than the others? Or is it up to personal preference as a programmer? I'm pretty new to this, trying to teach myself python and batch scripting concurrently. – Insarov Mar 07 '13 at 16:55
  • I haven't done proper testing. My personal opinion is the #2 would probably be better than either of the #1 variations. The filtering is more or less the same in both cases, but #2 filters all the items in one go, which must be faster then testing every item individually. And, because the list of items is cut down *before* the loop starts, #2 performs fewer iterations too. On the other hand, of course, iterating over files in a directory tree may be more efficient than iterating over lines of a command's output, but I'm not sure to what extent that would counterbalance the performance. – Andriy M Mar 07 '13 at 19:15
0

Answer 3 above, using ROBOCOPY, creates a tree of (possibly empty) subdirectories.

The following requires the obtaining of xxcopy

xxcopy c:\filematch d:\dest\ /SGF /RC

copies from c: to folder d:\dest

/SGF recurses subdirectories but flattens the result at the destination. In the event of filename collision, it appends .0001 to the first duplicate filename. So /SGF copies every matching file from the source drive, no matter what subdirectory it occupies, into a specified destination folder.

/RC removes the files from the source following a successful copy, AKA it moves them.

Not sure if it is what the OP wanted, but this discussion helped me!