BATCH Find string in subfolders and move to new location - windows

I'm currently trying to find a string in multiple files.... for example 'Apple' once found i would like to move the files which contain 'Apple' to a new folder.
This is my current script:
findstr /s /m /l /c:"Apple" "C:\Users\User\Desktop\created\*.php"
This finds all of the .php pages which includes the word 'Apple', however it currently lists them, i can't seem to move them into a new location.
I understand i will need to delete "/m" as this prints the file names...
So how do i move them into a new folder?
Thank you

put a for loop around:
for /f "delims=" %%a in ('findstr /smlc:"Apple" "C:\Users\User\Desktop\created\*.php"') do ECHO move "%%~fa" "Z:\New Location\"
Note: this is batch file syntax. For use directly on command line, replace every %% with a single %.
This just echoes the move commands. After troubleshooting, remove the ECHO to arm the move command.

A slightly different alternative, (creates as required a new directory named as the search word, to move it into, and only moves if the file does not already exist in there):
#Echo Off
Set "strPath=%UserProfile%\Desktop\created"
Set "strExtn=.php"
Set "strWord=Apple"
Set "strDest=%UserProfile%\Desktop\test"
CD /D "%strPath%" 2>Nul || Exit /B
For /F "Delims=" %%A In (
'Findstr /MISC:"%strWord%" "%strPath%\*%strExtn%" 2^>Nul'
) Do RoboCopy "%%~dpA." "%strDest%\%strWord%" "%%~nxA" /MOV>Nul
Just modify the values of the variables, lines 2-5, as necessary.

Related

Batch file with a recursive for loop to move file

I am trying to create a batch script to move files base on search criteria into another folder of the same subfolder structure.
I tried the following but the result is not quite right.
for /r "c:\Test_Copy\Source1\" %%x in (Test*.txt) do move "%%x" "c:\Test_Copy\Target1\"
As it is showing
move "c:\Test_Copy\Source1\Sub1\Test1.txt" "c:\Test_Copy\Target1\"
move "c:\Test_Copy\Source1\Sub2\Test1.txt" "c:\Test_Copy\Target1\"
I would like the outcome to be the following.
move "c:\Test_Copy\Source1\Sub1\Test1.txt" "c:\Test_Copy\Target1\Sub1\Test1.txt"
move "c:\Test_Copy\Source1\Sub2\Test1.txt" "c:\Test_Copy\Target1\Sub2\Test1.txt"
How will I be able to achieve this?
Thanks
The for /R loop returns full absolute paths, even the ~-modifiers do not allow to return relative paths. However, you could use xcopy /L, which just lists files that it would copy without the /L option, with paths relative to the source root directory; that list can easily be captured and processed by a for /F loop:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=C:\Test_Copy\Source1"
set "_DESTIN=C:\Test_Copy\Target1"
rem // Change into source root directory:
pushd "%_SOURCE%" && (
rem /* Run `xcopy /L` to list files but not actually copy any, because this returns
rem paths relative to the source root directory; then let `for /F` capture that
rem list, split off the preceding drive letter and skip the summary line: */
for /F "tokens=2 delims=:" %%F in ('
xcopy /L /S /Y "Test*.txt" "%TEMP%"
') do (
rem // Create potentially needed sub-directory, suppress errors when it exists:
2> nul md "%_DESTIN%\%%F\.."
rem // Actually move the currently iterated file into the destination directory:
move "%%F" "%_DESTIN%\%%F"
)
rem // Return from source root directory:
popd
)
endlocal
exit /B
The great advantage of this method is that no string manipulation is involved to derive relative paths, which is dangerous as it could fail in certain situations (for instance, when a root path like D:\ is given, or when a path like D:\some\.\source\dummy\..\folder is specified).
Of course you can also use robocopy /L as suggested in a comment by user Mofi:
robocopy "C:\Test_Copy\Source1" "C:\Test_Copy\Target1" "Test*.txt" /S /MOV /NDL /NJH /NJS
#echo off
for /D /R "c:\Test_Copy\Source1\" %%I in (*)do pushd "%%~I" & (
2>nul >nul mkdir "c:\Test_Copy\Target1\%%~nxI"
move "%%~I\Test*.txt" "c:\Test_Copy\Target1\%%~nxI" & popd
)
Outputs command loop results:
move "c:\Test_Copy\Source1\Sub1\test_001.txt" "c:\Test_Copy\Target1\Sub1\test_001.txt"
move "c:\Test_Copy\Source1\Sub1\test_002.txt" "c:\Test_Copy\Target1\Sub1\test_002.txt"
move "c:\Test_Copy\Source1\Sub1\test_003.txt" "c:\Test_Copy\Target1\Sub1\test_003.txt"
move "c:\Test_Copy\Source1\Sub2\test_001.txt" "c:\Test_Copy\Target1\Sub2\test_001.txt"
move "c:\Test_Copy\Source1\Sub2\test_002.txt" "c:\Test_Copy\Target1\Sub2\test_002.txt"
move "c:\Test_Copy\Source1\Sub2\test_003.txt" "c:\Test_Copy\Target1\Sub2\test_003.txt"
The move command results:
c:\Test_Copy\Source1\Sub1\test_001.txt
c:\Test_Copy\Source1\Sub1\test_002.txt
c:\Test_Copy\Source1\Sub1\test_003.txt
3 file(s) moved.
c:\Test_Copy\Source1\Sub2\test_001.txt
c:\Test_Copy\Source1\Sub2\test_002.txt
c:\Test_Copy\Source1\Sub2\test_003.txt
3 file(s) moved.
Obs.: If all your subfolders c:\Test_Copy\Target1\Sub[n] already exist, remove line 2>nul >nul mkdir "c:\Test_Copy\Target1\%%~nxI"
#echo off
For /D /R "c:\Test_Copy\Source1\" %%I in (*)do pushd "%%~I" & (
move "%%~I\Test*.txt" "c:\Test_Copy\Target1\%%~nxI" & popd
)
Try using for /D /R:
FOR /R - Loop through files (recursively)
FOR /D - Loop through several folders/directories
The option /D /R is undocumented, but can be a useful combination, while it will recurse through all subfolders the wildcard will only match against Folder/Directory names (not filenames)
Source linked to ss64.com
Rem :: Set your folder /Directory /Recursively tree starting at "c:\Test_Copy\Source1"
For /D /R "c:\Test_Copy\Source1"
If you want to do it with batch you need to modify the value of %%x to point to the target directory INSIDE the loop. When you do this you can NOT use % to surround the variables you create inside the for loop - you have to use delayed expansion with ! to surround those variables. Then you can use variable replacement on %%x to change it's value.
Like the comments say, this doesn't work if your directory/file names contain more than one exclamation point.
This does what you want I think:
#echo off
setlocal enabledelayedexpansion
set sourcedir=c:\Test_Copy\Source1\
set targetdir=c:\Test_Copy\Target1\
for /r "%sourcedir%" %%x in (Test*.txt) do (
set sourcefile=%%x
set destfile=!sourcefile:%sourcedir%=%targetdir%!
echo move !sourcefile! !destfile!
)
Just change echo move to move when you are ready to actually do the move.

Batch rename: skipping already renamed files

so in one other recent question i needed to find a solution to bulk renaming files by adding .ab into the filename. I succeeded in doing that, but now i face a different problem. Every time i run the batch file, it appends .ab to all the files even those, already renamed. I tried fixing the problem in the following way, which doesn't work.
rem #echo off
FOR /R "C:\Users\" %%G in (*.txt) DO (
%%G|findstr /i /L ".ab">nul
IF errorlevel 1 (
REN "%%G" "%%~nG.ab.txt"
) ELSE (
skip %%G
)
)
pause
Essentially i need to check if the file name already contains ".ab" in its name and then either skip or add .ab depending on the result. I would appreciate any help.
Use a For /F loop, instead of For /R. In addition, instead of using the Dir command with its /S option, (which will output items ending with .txt*), use Where with its /R option instead, (which will output items ending with .txt).
Single line batch-file example, (excludes those basenames ending with, not containing, .ab):
#For /F "Delims=" %%G In ('^""%__AppDir__%where.exe" /R "C:\Users" "*.txt" 2^>NUL^|"%__AppDir__%findstr.exe" /IV "\.ab\.txt$"^"')Do #Ren "%%G" "%%~nG.ab%%~xG"
Don't forget to change C:\Users and/or both instances of .txt and ab as/if necessary.

Batch file that looks for a folder that contains 1 file

i have a lot of folders with a random number of files within.
And the most of them just have 1 file inside it, these files needs to move to the parent folder. but i don't know how i should do it with a batch file.
I use Windows 7 Ultimate
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
FOR /d /r "%sourcedir%" %%a IN (*) DO (
FOR /f %%c IN ('dir /b/a-d "%%a\*.*" 2^>nul ^|find /c /v ""') DO IF %%c==1 ECHO(MOVE "%%a\*.*" "%%a\..\"
)
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
The for /d /r finds all of the subdirectory names starting at sourcedir and assigns thenm to %%a in turn.
Each directory is then examined for filenames only; the 2>nul suppresses error messages for empty directories, and the output of the dir command is fed to find which counts (/c) the number of lines which don't match "" (ie. counts the lines of directory = # files returned). This is applied to %%c
If %%c is 1, then move all (one) files from the directory to its parent.
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)
This solution don't use any external .exe command, so it should run faster. Also, it is clear enough to be understood with no problems, I think...
#echo off
setlocal EnableDelayedExpansion
for /D %%d in (*) do (
set "firstFile="
set "moreThanOneFile="
for %%f in ("%%d\*.*") do (
if not defined firstFile (
set "firstFile=%%f"
) else (
set "moreThanOneFile=true"
)
)
if not defined moreThanOneFile move "!firstFile!" "%%d"
)
You have a number of folders that all may or may not contain files within them, and you want to move all files to some other directory?
PowerShell is the new and improved super charged version of using a batch file, and this is how you'll do it.
Run PowerShell
paste in the following
dir -Recurse C:\FolderContainingManySubfolder | ? PSIsContainer | dir -Recurse | move-item -Destination T:\somePath -WhatIf
Replace C:\FolderContainingManySubfolder with the folder that has all of those other folders with one or two items each, and replace T:\somePath with the place you want the single files to go.
Run it, and you'll see a lot of 'What If' output, which shows you what would happen if you were to run the command. If you're happy with what you see, then remove the -WhatIf parameter from the end.

Remove all blank lines from *.txt files in the directory and subfolders in Windows

Searching, trying and crying I developed a code:
For /R %%G IN (*.txt) do for /f "delims=" %%a in ('more +1 %%G ^| find /v ""') do (set line=%%~a echo !line!) > new\%%G
Do someone know why does it loop forever?
What it is expected to do, is to remove blank lines in every *.txt file it founds in all subdirectories and put the new file with the same name in "new" folder. I can provide all "new" folders needed manually.
I'm not sure this would cause it to loop forever, but you are writing to a NEW folder that is in the same hierarchy that you are reading from. So it will process files that you just wrote. You will need a filter to prevent that.
Also, I think your output file name needs %%~nxG to get just the file name and extension, without the path.
There is a much simpler way to strip out blank lines. findstr . file will strip out empty lines. findstr /rc:"[^ ] will strip out empty lines and lines that contain only spaces.
#echo off
setlocal
set "outFolder=new"
for %%F in ("%outfolder%\.") for /r %%G in (*.txt) do if "%%~dpG" neq "%%~fF\" findstr /rc:"[^ ]" "%%G" >"%%~fF\%%~nxG"
But the simplest thing to do is just make sure your output folder is distinct from your source hierarchy
for /r %%G in (*.txt) do findstr /rc:"[^ ]" "%%G" >"\distinctPath\%%~nxG"
UPDATE
One thing that could cause your script to hang is that piped MORE will hang if the file has more than 64k lines. But I don't understand why you are using MORE in the first place.

using the command line how can i modify filenames

how can i modify filenames in a folder based on delimiters in the filename?
I have a folder with images that get picked up by a different program based on a schedule- the program can only analyze the images if it contains just the main name (sku#) not the additional data that the photographers add after the name
using the command line can i run some sort of script to modify the filenames & delete all characters from after an underscore or hyphen (also need to delete underscore or hyphen)
(i dont know if & how its possible to do this thru the windows command line but i do have the option of running such a 'script' in cygwin- I prefer to use whatever works best...)
I haven't had a need to do this: but with a quick search I found this link on another Stack Exchange site.
A few people uploaded some powershell scripts. The top answer is a GUI tool to do mass name-changes.
There is this CMD example:
dir /B > fileList.txt
for /f "tokens=1,2,3" %i in (fileList.txt) DO ren "%i %j %l" %l
The first line outputs the list of files into a file called fileList.txt. The second line separates each of the names in the list into 3 parts, the #, the "-" and the rest of the name. For each of those it does the rename command.
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%a IN ('dir /b /a-d ^|findstr "_ -"') DO (
FOR /f "delims=_-" %%i IN ("%%a") DO ECHO REN "%%a" "%%i%%~xa" 2>nul
)
FOR /f "delims=" %%a IN ('dir /b /a-d ^|findstr "_ -"') DO ECHO failed ON "%%a"
This should do the job.
First step is to perform a directory listing in /b basic form (without headers - names only) and /a-d without directory names. This is filtered by findstr on (either underscore or dash) and %%a acquires each filtered filename in turn.
The next step is to take those filenames and split them into the parts on either _ or -. The first token (up to, but not including the delimiter) is applied to %%i, so the rename required is from "%%a" (the original filename) to "%%i%%~xa" - the first token+the extension from the original filename.
It's quite possible that the attempt to rename will fail because the new name already exists, so the error message is simply ignored (2>nul)
Finally, look for any un-renamed files and report them (optional, of course)
Note that the REName command is merely ECHOed. This ensures nothing is actually changed while you verify this is what you want to do. Simply remove the ECHO before the REN to activate the rename.

Resources