0

I have the following folders:

Apple_folder
Pear_folder
Tomatoes_folder

Within Apple_folder, I have the following files:

Extracted-Apple_1.txt
Extracted-Apple_2.txt
Extracted-Pear_1.txt
Extracted-Pear_2.txt
Extracted-Apple_3.txt
Extracted-Tomatoes_1.txt

How do I move Extracted-Pear_1.txt, Extracted-Pear_2.txt, Extracted-Tomatoes_1.txt to their relevant folders, i.e. keep file name that contain apple under Apple_folder, etc.

Expected Apple_folder contents:

Extracted-Apple_1.txt
Extracted-Apple_2.txt
Extracted-Apple_3.txt

I am still a beginner in batch script, so not sure how to proceed?

for %%a in (*.txt) do (
   echo %filename%    
   for /f "tokens=* delims=- _" %%f in (%filename%) do (
      if tokens==Pear move Extracted-Pear*.txt   "C:\Users\ABCD\Documents\Pear_folder\"
      if tokens==Tomatoes move Extracted-Pear*.txt "C:\Users\ABCD\Documents\Tomatoes_folder\"
   )

I am using this code to try to rename the files to avoid overwriting files with similar name in the destination folder.

setlocal enabledelayedexpansion
set /A counter=0

@echo off
for %%a in (*.txt) do (  
set /A counter+=1
    for /f "tokens=2 delims=-_" %%f in ("%%a") do (
        move Extracted-%%f_*.txt "C:\Users\ABCD\Documents\%%f_folder\Extracted-%%~nf_moved_!counter!.txt"
    )
)

only one file gets moved/renamed and then get an error message

"Cannot move multiple files to a single file."
Nbl123
  • 47
  • 7
  • Hint: use a [for](http://ss64.com/nt/for.html) loop to iterate files and a [for /f](http://ss64.com/nt/for_f.html) to split file names at the delimiters `-_` –  Jul 22 '19 at 13:02
  • read again the [for /f](https://ss64.com/nt/for_f.html) documenation. Especially take a look at the examples at the bottom of the page. Your understanding of `tokens` and `delims` seems to be wrong. – Stephan Jul 22 '19 at 13:59
  • You have unbalanced parentheses. I have formatted and indented your code to make it easier for you to notice that issue. – Compo Jul 22 '19 at 14:00
  • thanks @LotPings, I will need to do some research as I haven't done this type of operations before. – Nbl123 Jul 22 '19 at 14:00
  • Thanks @Compo for your help. – Nbl123 Jul 22 '19 at 14:04

2 Answers2

0

Apart from the missing ) mentioned by Compo, there is a misunderstanding of how tokens and delims work. See SS64 for more information about that.

For the variable filename to work, you need delayed expansion, but you can work without that by using the for variable (%%a) directly:

@echo off
for %%a in (*.txt) do (
   for /f "tokens=2 delims=-_" %%f in ("%%a") do (
      ECHO move Extracted-%%f_*.txt  "C:\Users\ABCD\Documents\%%f_folder\"
   )
)

A few explanations to the tokens and delimiters part:

The for /f loop disassembles the string into "tokens" by splitting it at the "delimiters":

tokens=* tells for to get the whole string, disregarding the delimiters (simplified version - in reality it's a bit more complicated).

Extracted-Apple_1.txt delimited by - and _ gives you three tokens: Extracted, Apple and .txt, the first token named %%f (given by you), the next are just named with the following letters. Token 2 would be %%g and token 3 would be %%h.

Now it gets interesting: With tokens=2 you tell for to just take the second token (which would go to %%f(!), as it's the first (and only) returned token)

So this leads to the "tokens=2 delims=- _" above.

Note I disabled the move command by just echoing it (for security and troubleshooting). Only when it works as intended, just remove the ECHO to enable the move command.

Edit to comply to the "no overwrite" request:

@echo off
setlocal enabledelayedexpansion
set "counter=0"
for /f "delims=" %%a in ('dir /b *.txt') do (
    for /f "tokens=2 delims=-_" %%f in ("%%a") do call :FileMove "%%a" "%%f"
)
pause
goto :eof

:FileMove
set counter=0
:FileNext
if exist "C:\Users\NABIL\Documents\TESTING\Batch_script\%~2_folder\%~n1_moved__%counter%.txt" (
  set /a counter+=1
  goto :fileNext
)
md "C:\Users\NABIL\Documents\TESTING\Batch_script\%~2_folder\" 2>nul
MOVE "%~1" "C:\Users\NABIL\Documents\TESTING\Batch_script\%~2_folder\%~n1_moved__%counter%.txt"
goto :eof

I "outsourced" the renaming and moving to a subroutine, mainly because we need a goto, which is not possible within a code block. I also changed your destination file naming scheme to what I think you want, but I might be wrong - so please check that out.

Stephan
  • 53,940
  • 10
  • 58
  • 91
  • Grateful for your help. Many thanks for the explanation. I ran it but it's giving an error: _" was unexpected at this time.. – Nbl123 Jul 22 '19 at 14:59
  • Edited. (It was the space at `delims=- _` - I copy/pasted that from your question; We don't want the space as a delimiter - if we would want it, the space would have to be the last character) – Stephan Jul 22 '19 at 15:05
  • It works after removing the space in delims. Thank you very much for your help @Stephan. You're a star! – Nbl123 Jul 22 '19 at 15:08
  • I just have a bit of experience with `for` loops (the Terry Pratchett quote at the bottom of the linked site isn't there for no reason `;)`). – Stephan Jul 22 '19 at 15:16
  • Would you be able to tell why the script above doesn't work? Thank you ! – Nbl123 Jul 23 '19 at 18:38
  • How does it not work? What doesn't happen although expected and what does happen although not expected? – Stephan Jul 23 '19 at 18:48
  • When I move the files to relevant folders. The folders may have files with the same names and I don't want them overwritten (I believe MOVE can only overwrite), hence the need to rename them before moving them (adding moved_counter), e.g. Extracted-Tomatoes_moved_6.txt. when i ran the script, only when file gets renamed and moved as intended and then I get the error message "Cannot move multiple files to a single file." for the rest of files. – Nbl123 Jul 24 '19 at 07:35
  • There is no built-in way to do that. You need to check the destination (`if exist "C:\Users\ABCD\Documents\%%f_folder\%%~nxa"), add a counter and loop until there is no such file. – Stephan Jul 24 '19 at 16:06
  • [Search](https://stackoverflow.com/search?q=%5Bbatch-file%5D+copy+without+overwrite) – Stephan Jul 24 '19 at 16:07
  • The following script that I have just posted moves the files. However, it it does it twice on the first file. Extracted_Apple_1 becomes Extracted_Apple_moved_1 then Extracted_Apple_moved_4. Not sure where the glitch is? – Nbl123 Jul 29 '19 at 14:50
0

setlocal enabledelayedexpansion
set /A counter=0

@echo off
for %%a in (*.txt) do (
    for /f "tokens=2 delims=-_" %%f in ("%%a") do (
set /A counter+=1 
MOVE "%%a" "C:\Users\ADMIN\Documents\TESTING\Batch_script\%%f_folder\Extracted-%%~nf_moved__!counter!.txt"
    )
)
pause

Nbl123
  • 47
  • 7
  • the `for %%a in (*.txt)` processes (dynamically) all `*.txt` files If you create new matching files during that process, those may be processed also. Better: `for /f "delims=" %%a in ('dir /b *.txt') do...`. The `dir /b *.txt` is executed once and the `for /f` loop processes its (static) output. You also forgot to check the existence at the destination before moving. – Stephan Jul 29 '19 at 15:10
  • Could someone have a go at this and let me know please !! – Nbl123 Jan 25 '20 at 08:51