batch-filemovexcopyfile-organization

Batch move with exceptions? Or using xcopy and deleting original after?


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


Solution

  • 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.