-1

I'm trying to put together a Windows batch script that moves the most recent file to a different directory. Here's my batch script mostly stolen from here:

FOR /F "tokens=*" %%G IN ('dir /b *.*') DO move %%G C:\Users\jrobinson\Desktop\ & exit /b

When I run this it moves every file in the folder. Interestingly, when I replace the MOVE command with a COPY command, the script copies only one file:

FOR /F "tokens=*" %%G IN ('dir /b *.*') DO copy %%G C:\Users\jrobinson\Desktop\ & exit /b
REM ---------------------------------------^^^^

Why is the move script moving every file while the copy script is only copying one file? Is it possibly because my script file is also in that folder and because of my edits, it is the most recent file?

Edit: Here are the contents of my source folder:

  • myBatchFile.bat
  • newest.txt
  • oldest.txt
  • second.txt

Of the *.txt files, newest.txt has the most recent modified date. Of all of the files regardless of extension, myBatchFile.bat has the most recent modified date given that I keep making edits to it to try to get it to work.

Edit #2: Here's a screenshot of my command window after running the first command above. This shows that all of the files in my source folder are copied when I only expect the newest file to be copied.

enter image description here

6
  • 1
    I'd use dir /b /o:-d /a:-d *.*, so you sort items by date (newest first) and exclude directories; instead of %%G I recommend using "%%~fG to provide the full path; for the sake of readability I'd put parenthesis () around the code after do (although I think that does not make any difference in operation)...
    – aschipfl
    Commented Oct 9, 2015 at 13:56
  • @aschipfl, it'd take you as much effort to write it in an answer, probably adding an explanation that "your posted code repeats the do action for every file, so you should exit the loop after moving the file by using goto, for example`.
    – woxxom
    Commented Oct 9, 2015 at 14:40
  • @wOxxOm, The repeated "DO" is not causing the problem with the my second command, the one that uses COPY instead of MOVE. My second command copies only one file even though the folder contains several files. Commented Oct 9, 2015 at 14:58
  • @user2023861, sorry, I was blind. Indeed, it's strange since both your examples should exit after the first file is processed.
    – woxxom
    Commented Oct 9, 2015 at 15:04
  • @wOxxOm, I provided an answer as requested...
    – aschipfl
    Commented Oct 9, 2015 at 15:37

3 Answers 3

2

I'd use dir /b /o:-d /a:-d *.*, so the items are sorted by date (newest first) and directories are excluded. Otherwise the sort order is not clear, and directories like . (current) or .. (parent) might be returned unintentionally.

Instead of %%G I recommend using "%%~fG" to provide the full path, surrounded by doublequotes. Also the destination path should be enclosed in "" to avoid troubles with whitespaces.

The FOR /F should be changed to "delims=" in case the file name starts with a space (which I think is valid in Windows). "tokens=*" removed them.

Furthermore, I'd put parenthesis () around the code after do (so it is guaranteed and obvious that both commands move and exit /b are part of the loop context).

So all in all this leads to the following code:

FOR /F "delims=" %%G IN ('dir /b /o:-d /a:-d *.*') DO (move "%%~fG" "C:\Users\jrobinson\Desktop\" & exit /b)

Since the newest file is enumerated first and the for body contains exit /b (exit batch file), only that file is moved.
If you need to execute some other code after this line, replace exit /b by goto :SKIP (or any other valid label), and state the label (:SKIP) immediately after the FOR command block.


If the batch script containing the code herein is located in its working directory, moving it (in case it is the newest file) most likely results in unexpected behaviour. You can exclude the batch script itself by filtering it out using find like this:

FOR /F "delims=" %%G IN ('dir /b /o:-d /a:-d *.* ^| find /v /i "%~nx0"') DO (move "%%~fG" "C:\Users\jrobinson\Desktop\" & exit /b)

%~nx0 therein expands to the file name and extension of this script (see call /?).

6
  • That didn't work. It still moves all of the files in my source folder rather than just the newest file. I found that if I change the wildcard in the dir command from *.* to *.txt, it will move only the newest *.txt file. This is true even if I have multiple *.txt files in my source folder. Commented Oct 9, 2015 at 18:12
  • That's weird! I'll try to figure it out... so your batch is the newest file in the source directory? what if you place another file there which is newer -- does it work then?
    – aschipfl
    Commented Oct 9, 2015 at 22:55
  • it does. I put in a newer text file and the script only copied that file. It looks like it works as long as the script file is not the newest file being moved. Probably what I'll have to do is keep the script in a separate folder. Thanks. Commented Oct 12, 2015 at 13:02
  • cmd does not buffer a batch file in memory for execution, I think this disrupts the for loop; so you could 1. place the batch file somewhere else, or 2. exclude it from being processed programmatically; if you want to go for option 2., I can regard it in my answer, just let me know
    – aschipfl
    Commented Oct 12, 2015 at 15:15
  • wow. For your option #2, is that what the other user posted below concerning %~nx0? I'm guessing that that's the variable name for the file? Commented Oct 12, 2015 at 15:38
0

I'm not sure I believe what you say. Because when I type the same command, is a file that I see first followed by the PAUSE command (or exit)

FOR /F "tokens=*" %G IN ('dir /b *.*') DO @echo  %G & pause

So it always goes first action on the first file and the script will stop.

See this 5 secs gifv: http://i.imgur.com/kyHdN1Y.gifv with the following code:

@echo off

if exist ..\destination-test-folder\nul rd /s /q ..\destination-test-folder
if not exist ..\destination-test-folder\nul md ..\destination-test-folder

copy nul newest.txt>nul
copy nul oldest.txt>nul
copy nul second.txt>nul
dir /b .
pause>nul

echo: &echo For loop command: &echo:
for /f "tokens=*" %%g in ('dir /b "*.*"') do if "%%g" neq "%~nx0" move %%g ..\destination-test-folder>nul & echo pause is stated after each iteration & echo         1 file(s) moved. &pause>nul

echo: &echo list destination:
dir /b "..\destination-test-folder" &echo: &echo list source: &echo: 
dir /b . 
3
  • I don't know how to prove to you that I'm not making this up. I don't know why someone would make this up. The only difference between the command I have that effects only one file and the command I have the effects every file is that the former is a COPY and the latter is a MOVE. Commented Oct 9, 2015 at 18:21
  • I posted a screenshot in my question that shows all of the files being moved Commented Oct 9, 2015 at 18:30
  • I tried your one line loop and it echoed only the name of the newest file. But I replaced the echo command with a MOVE command, and it moved every file in my source folder. However, I pulled the loop out of your code block and inserted a MOVE command, for /f "tokens=*" %%g in ('dir /b "*.*"') do if "%%g" neq "%~nx0" move %%g ..\ & exit /b and this worked. I think that condition fixed it, but I don't know what %~nx0 means. Can you explain? Commented Oct 9, 2015 at 20:19
0

Just wanted to say thanks person: aschipfl You are my hero.

here is the command I used to move all read only files to a sub folder "temp"

md temp
FOR /F "delims=" %%G IN ('dir /b /o:-d /a:R *.*') DO (move "%%~fG" "temp" )

Not the answer you're looking for? Browse other questions tagged or ask your own question.