I have cracked my head up...
Now I have a folder containing empty subfolders and pictures.
These pictures are randomly named as their default name generated by the camera.
If I want to sort these pictures out into a few batches and then move them into the subfolders
For example:
lets say in total I have 100 pictures and five 5 subfolders.
first 20 pictures into subfolder_1
subsequent 25 pictures into subfolder_2
subsequent 23 pictures into subfolder_3
subsequent 12 pictures into subfolder_4
lastly the remaining 20 pictures into subfolder_5
So, I am thinking of doing it in loops. and since the number of pictures are not constant, and I intend to prompt the user to define number of pictures to be moved each time.
The main thing that I couldn't figure out is that HOW DO I CONTROL THE NUMBER OF LOOPS TO BE DONE?
I know about using GOTO function to break a FOR loop. But I am not sure how to do it in my case.
In fact, I am now still stucked with this concept I currently have, where I tried to use a shorter FOR loop to contain an longer FOR loop like this:
(this is just to try for the first 20 pictures into subfolder_1)
FOR /L %%A in (1,1,20) Do (
FOR %%B in ("%dir_of_folder_which_contains_the_pictures_and_subfolders%\*") Do (
MOVE *.jpg subfolder_1
)
)
These codes don't work. Perhaps it has got to be using GOTO function? Can anyone help? THANKS ALOT..
#echo off
setlocal enableextensions enabledelayedexpansion
set "folder=%cd%"
rem For each of the present subfolders
for /d %%a in ("%folder%\*") do (
rem Count the number of remaining files
set "nFiles=0"
for /f %%b in ('dir "%folder%\*" /a-d /b 2^>nul ^| find /c /v ""') do set "nFiles=%%b"
if !nFiles! lss 1 goto :done
rem Ask the number of files to move
echo(
echo(There are !nFiles! files left. How many to move to %%a ?
set "nFiles=0"
set /p "nFiles="
set /a "nFiles+=0" 2>nul
rem Move the indicated number of files
if !nFiles! gtr 0 for %%c in ("%folder%\*") do if defined nFiles (
echo move "%%~fc" "%%~fa"
set /a "nFiles-=1"
if !nFiles! equ 0 set "nFiles="
)
)
:done
endlocal
exit /b
Not the most efficient code, but this is a basic skeleton to build from. The move command has been prefixed with a echo for testing. If the output to console is correct, remove the echo.
This type of problems may be solved in a better way with the use of data structures, like arrays or lists. For example:
#echo off
setlocal EnableDelayedExpansion
rem Initialize counters
set /A numFolders=0, numFiles=0
rem Save file names in an array
for %%a in (*.*) do (
set /A numFiles+=1
set "file[!numFiles!]=%%a"
)
rem Save folder names in a list
set "list="
for /D %%a in (*) do (
set /A numFolders+=1
set "list=!list! %%a"
)
rem Ask the user for the distribution
:askDistribution
echo There are %numFiles% files and %numFolders% folders
echo Enter the number of files for each folder (must sum %numFiles%)
echo Folders: %list%
set /P "distribution=Files: "
set total=0
for %%a in (%distribution%) do set /A total+=%%a
if %total% neq %numFiles% goto askDistribution
rem Distribute the files
set i=0
for %%n in (%distribution%) do (
rem Get current folder and shift the rest
for /F "tokens=1*" %%a in ("!list!") do (
set folder=%%a
set list=%%b
)
rem Move the files
for /L %%i in (1,1,%%n) do (
set /A i+=1
for /F %%i in ("!i!") do ECHO move "!file[%%i]!" !folder!
)
)
For further details, see: Arrays, linked lists and other data structures in cmd.exe (batch) script
Related
i am making a file selector which would randomly copy files from one folder to another code works quite fine but sometimes it shows The system cannot find the path specified for all or majority of files i don't know what went wrong can please someone help
my code
#echo off
setlocal enabledelayedexpansion
set num=0
cls
set /p input= enter the number of files you want:
set /p address= enter the address of your files:
md SelectedFiles
pushd "%address%" || goto :EOF
set /a num=%num%+1
for /f "tokens=1,* delims=[]" %%i in ('dir /b /s /a-d ^| findstr /RV "[.]jpg [.]png" ^| find /v /n ""') do (
set "file%%i=%%~j"
set "cnt=%%i"
)
for /l %%c in (1,1,%input%) do (
set /a rand=!random! %% !cnt!
for %%r in (!rand!) do copy "!file%%r!" "%address%\SelectedFiles" | clip
)
echo your files have been copied
pause
popd
Try, as a replacement for your for /l loop
for /l %%c in (1,1,%input%) do (
set /a rand=1 + !random! %% !cnt!
for %%r in (!rand!) do (
copy "!file%%r!" "%address%\SelectedFiles" | clip
for %%s in (!cnt!) do set "file%%r=!file%%s!"
set /a cnt-=1
)
)
Your filenames are currently being assigned to file1..file!cnt!.
You are then generating rand as 0..cnt-1, so there is a probability that you will choose file0 which does not exist and no possibility of choosing file!cnt!
There is also a possibility of re-choosing a file.
You should make sure that input is not greater than cnt.
My suggested code simply makes the range 1..cnt, then when a file has been processed, moves the very last filename (file!cnt!) over the chosen name and reduces cnt since there is one fewer filename in the list.
NOTE: Since the |clip is piping from a copy statement for one file only, it should only ever generate 1 file(s) copied. on the clipboard
I am trying to remove a tag from a set of html files and I can't seem to find the right commands to do the job.
I am able to find the line number of the tag; the tag is a total of 10 lines that need to be deleted. Once I find this line, how do I got and delete said line & next 10 lines?
Here's what I have (a first for loop to collect files, a second for loop that collects all line numbers.) thank you.
::start by creating a list of html files
set i=0
for /r %%G in (*.html) do (
set /A i+=1
set array[!i!]=%%G
)
set n=%i%
::second nested loop collects all lines for bottom secion to be deleted.
set j = 0
for /L %%i in (1,1,%n%) do (
for /f "delims=" %%a in ('findstr /n /c:"u-backlink u-clearfix u-grey 80" !array[%%i]!') do (
set var=%%a
set /A j+=1
set array[!j!]=!var:~0,3!
)
)
set m=%j%
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory & destination directory are names
rem that I use for testing and deliberately include names which include spaces to make sure
rem that the process works using such names. These will need to be changed to suit your situation.
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
for /r "%sourcedir%" %%G in (*.html) do (
SET "linecount="
FOR /f "delims=:" %%e IN ('findstr /n /c:"u-backlink u-clearfix u-grey 80" "%%G"') DO SET /a linecount=%%e
IF DEFINED linecount (
FOR /f "usebackqdelims=" %%b IN ("%%G") DO (
SET /a linecount-=1
IF !linecount! gtr 0 ECHO %%b
IF !linecount! lss -10 ECHO %%b
)
)>"%destdir%\tempfile"& MOVE /y "%destdir%\tempfile" "%%G" >nul
)
GOTO :EOF
Start a recursive directory list of the target files from sourcedir.
Initialise linecount to nothing and use findstr to locate the target string. %%e will be set to the number of the line found, set this into linecount.
If the string was found, linecount will now contain a value, so read each line and count down. If linecount is between 0 and -10, we don't echo the line to the output file.
I originally put all the generated files in the one directory. Yours to change at will.
Revised to generate a temporary file (quite where would be irrelevant) and then move that file over the original.
Always verify against a test directory before applying to real data.
I need a batch process to duplicate a file specified number of times.
Currently I repeatedly copy paste in order to multiply a file .
I've scoured the internet for .bat codes which does this.
With no luck ; I'm not a programmer.
Hoping for something simple as drag drop . Setting number of duplicates needed within the .BAT itself without heavy use of CMD .
If possible I need something as simple to duplicate a file specified number of times.
Now that you better explained your requirement in a comment, this would seem to be what you need.
#echo off
set /p num=Enter number of times you want to copy file:
for %%a in (*) do if not "%%~fa"=="%~0" (
set "fname=%%~a"
set "name=%%~na"
set "ext=%%~xa"
)
for /l %%i in (1,1,%num%) do copy "%fname%" "%name%%%i%ext%"
pause
The if not "%%~fa"=="%~0" is simply to ensure we do not do the same duplication for the batch file itself.
to add 1 less file than entered:
#echo off
set /p num=Enter number of times you want to copy file:
set /a num+=1
for %%a in (*) do if not "%%~fa"=="%~0" (
set "fname=%%~a"
set "name=%%~na"
set "ext=%%~xa"
)
for /l %%i in (1,1,%num%) do copy "%fname%" "%name%%%i%ext%"
pause
or to delete the original file:
#echo off
set /p num=Enter number of times you want to copy file:
for %%a in (*) do if not "%%~fa"=="%~0" (
set "fname=%%~a"
set "name=%%~na"
set "ext=%%~xa"
)
for /l %%i in (1,1,%num%) do copy "%fname%" "%name%%%i%ext%"
del "%fname%" /Q
pause
I'm attempting to use a batch file to keep all files in a particular folder numbered sequentially (0,1,2,...). To do this I first require knowing what the highest number in this sequence is so I can append the non-sequentially named files to the end of the list. For example, I may have the following files:
0.png
1.jpg
2.jpg
3.png
file_51.jpg
pictureabc.png
This would return a result of 3 as that is the last filename in sequence. I would then be able to find the remaining files (not sure the best way to do this either) and number them starting at 4.
The only solution I have come up with so far is using an infinite goto loop that stops when no filename including that number exists.
set count=0
:loop
if exist %count%.* set /a count+=1 & goto loop
This solution is highly inefficient however and takes almost a minute for 100 thousand images. I'm looking for a solution that will be able to achieve this in under 10 seconds if possible.
#echo off
setlocal enableextensions disabledelayedexpansion
setlocal enabledelayedexpansion
set "nextFile=0" & for /f "delims=" %%a in ('
dir /a-d /b ^| findstr /b /r /x
/c:"[1-9][0-9]*\.[^.]*"
/c:"[1-9][0-9]*"
/c:"0"
') do if %%~na geq !nextFile! set /a "nextFile=%%~na+1"
endlocal & set "nextFile=%nextFile%"
echo Next file will be: %nextFile%
This just uses a dir command to retrieve the list of all files, filtered with findstr to only get those with numeric name. The rest is just compare the file name against the previous max value.
Edited - This should work fast enough
#if (#This === #IsBatch)
#echo off
rem Start of batch zone ----------------------------------------------
setlocal enableextensions disabledelayedexpansion
for /f %%a in ('
dir /a-d /b /o-d
^| findstr /r /x /c:"[0-9][0-9]*\.[^.]*" /c:"[0-9][0-9]*"
^| cscript //nologo //e:jscript "%~f0"
') do set "nextFile=%%a"
echo next file will be %nextFile%
exit /b
#end
// Start of JScript zone ---------------------------------------------
var inputStream = WScript.StdIn;
var max = 0, value ;
while(!WScript.StdIn.AtEndOfStream) {
value = parseInt( inputStream.ReadLine().split('.')[0], 10 );
if ( value >= max ) max = value + 1;
}
WScript.StdOut.WriteLine( max );
This is an hybrid batch/jscript file. Saved as .cmd file, it uses a dir command to retrieve the list of files, a findstr to leave only the files with numbered names and then the native JScript engine to extract the numbers and search for the greatest value.
I think this is the fastest way:
#echo off
setlocal EnableDelayedExpansion
set lastNum=0
for /L %%a in (1,1,9) do (
for %%b in (%%a*.*) do (
if %%~Nb gtr !lastNum! (
set lastNum=%%~Nb
)
)
)
echo Last numbered file: %lastNum%
EDIT: New method added
Previous method depends on the number of existent files, so it is not as fast as I expected...
The new method below takes almost the same time no matter the number of files:
#echo off
setlocal EnableDelayedExpansion
set "names="
for /L %%i in (1,1,9) do set "names=!names! %%i*.*"
dir /B /A-D /O-D %names% 2> NUL | ( set /P "lastNum=" & set lastNum ) > lastNum.txt
for /F "tokens=2 delims==." %%a in (lastNum.txt) do set "lastNum=%%a"
del lastNum.txt
echo Last numbered file: %lastNum%
Previous method may fail if more than one of the last files have the same created time, but this point may be fixed if needed.
sorry - but the last method by Aacini works really bad. Actually it does not find the highest number, but the file created (not modified) last. It would be great to know how to fix this!
Stopping at hole can be fixed with iterations (yeah 2 lines of code for each subsequent hole).
here is how to iterate...
set count=1234 ::starting number
:loop
if exist %count%.img set /a count+=1 & goto loop
set /a count+=1
if exist %count%.img set /a count+=1 & goto loop
set /a count+=1
if exist %count%.img set /a count+=1 & goto loop
set /a count=%count%-2
need to reduce the count at the end again. This could be made much longer of course but then it will slow down if you iterate 1000 times...
I have a million old text files that I need to convert the format on. I have been desperately trying to do this myself but I really could use help. I am trying to convert data that looks like this:
text
11111.111
22222.222
33333.333
text2
44444.444
55555.555
66666.666
77777.777
88888.888
99999.999
(each number is on a seperate line and there are some blank lines, but I need them to go into the output file as a place keeper)
Into a .txt file that looks like this:
**I also need to add an increment number at the beginning of each line to number the lines.
1,11111.111,22222.222,33333.333,text
2,44444.444,55555.555,66666.666,text2
3,77777.777,88888.888,99999.999,
the files that I have are in separate folders in a directory and have no file extension but they behave exactly like a standard text file.
I have tried all sorts of stuff but I am just not that well versed in programming. Here is the little bit of code that I havent deleted for the 100th time. gettting frustrated
:REFORMAT
FOR %%F IN (*) DO IF NOT %%~XF==.BAT (
SETLOCAL DISABLEDELAYEDEXPANSION
(
SET /P LINE1=
SET /P LINE2=
SET /P LINE3=
SET /P LINE4=
)<"%%F"
ECHO %LINE2%,%LINE3%,%LINE4%,%LINE1%>>"%%F".TXT
PAUSE >NUL
:END
I am using windows I have access to dos6 dos7 winxp 32 and win7 64
the text and text2 are text strings within the file, they are descriptors telling me what the numbers below mean and some of the descriptors are left out. I also need it to process more than the first four lines. Some files have up to 200 lines inside of them. Thank you so much for helping me. thank you so much dbenham here is the final result:
#echo off
setlocal enableDelayedExpansion
for /R %%F in (*.) do (
set /a ln=0
for /f %%N in ('type "%%F"^|find /c /v ""') do set /a cnt=%%N/4
for /l %%N in (1 1 !cnt!) do (
for %%A in (1 2 3 4) do (
set "ln%%A="
set /p "ln%%A="
)
set /a ln+=1
echo !ln!,!ln2!,!ln3!,!ln4!,!ln1!
)
) <"%%F" >"%%F.CSV"
Using nothing but pure native batch:
#echo off
setlocal enableDelayedExpansion
for %%F in (*.) do (
set /a ln=0
for /f %%N in ('type "%%F"^|find /c /v ""') do set /a cnt=%%N/4
for /l %%N in (1 1 !cnt!) do (
for %%A in (1 2 3 4) do (
set "ln%%A="
set /p "ln%%A="
)
set /a ln+=1
echo !ln!,!ln2!,!ln3!,!ln4!,!ln1!
)
) <"%%F" >"%%F.txt"
The above will process all files that have no extension in the current folder. If you want to recursively include all sub-folders, then add the /R option to the outer FOR statement.
The whole thing can be done quite simply using my REPL.BAT utility:
#echo off
for %%F in (*.) do (
<"%%F" repl "([^\r\n]*)\r?\n([^\r\n]*)\r?\n([^\r\n]*)\r?\n([^\r\n]*)\r?\n?" "$2,$3,$4,$1\r\n" mx|findstr /n "^"|repl "^(.*):" "$1," >"%%F.txt"
)
just a few modifications:
set /p doesnt delete a variable if input is empty, so you have to delete it before.
You missed a closing paranthese )
You have to use delayed expansion to use a changed variable inside parantheses
the counter.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set count=0
FOR %%F IN (*.) DO IF NOT %%~XF==.BAT (
set "LINE1="
set "LINE2="
set "LINE3="
set "LINE4="
set count+=1
(
SET /P LINE1=
SET /P LINE2=
SET /P LINE3=
SET /P LINE4=
)<"%%F"
ECHO !count!,!LINE2!,!LINE3!,!LINE4!,!LINE1!>>"%%F.txt"
)
PAUSE >NUL
:END