Adding a textfile with a name to each directory - windows

I'm having some trouble with trying to add a text file to each directory in this directory having a certain name. I have a directory called Daily Notes where I save my notes for the day and I have this further organized by week. So I have a bunch of directories in here such as 6.5.17-6.10.17 and in each of these I need a text file with the name format such as 6.7.17DailyNotes.txt. I know I can easily do this by hand each day, but I have some free time and am trying to learn how to program with cmd. I tried to just make a test text file with a for loop but it saved it to the directory containing the batch file. Here is my code right now:
#echo off
setlocal disabledelayedexpansion
set "folder=%~1"
if not defined folder set "folder=%cd%"
for /D %%a in ("%folder%\*") do (
echo test > test.txt
)
endlocal
So, I want to go into each directory and make 5 text files, one for each day with the format month.day.yearDailyNotes.txt. I was thinking I could just make a variable from reading the directory name and count up in days from that for the text files. Any advice?

Your comment
I know it would be very difficult to handle month changes in the
middle of the week, I was thinking it will be acceptable to just
handle that part manually, so have a file named something like
10.32.17DailyNotes.txt which I manually will change after
makes it much easier (Date/Time Math in Batch is possible, but ugly and involves a lot of code)
#echo off
setlocal enabledelayedexpansion
REM next two lines for simulating your environment:
set "folder=%~dp0"
md 6.5.17-6.10.17 6.11.17-6.16.17 2>nul
REM for every folder
for /d %%f in ("%folder%*.*.*-*.*.*") do (
REM extract day, month and year [from first part of foldername]
for /f "tokens=1-3 delims=.-" %%a in ("%%~nxf")do (
REM calculate "end day" [may be greater than days in that month]
set /a end=%%b+5
REM for [start] to [end]
for /l %%i in (%%b,1,!end!) do (
REM create blank file
break > "%%f\%%a.%%i.%%cDailyNotes.txt"
)
)
)

Iterate over all of the subdirectories and create a test.txt file.
set "folder=%~1"
if not defined folder set "folder=%cd%"
FOR /F "usebackq tokens=*" %%a IN (`DIR /S /B /A:D "%folder%\*"`) DO (
ECHO test > "%%~a\test.txt"
)

#echo off
setlocal disabledelayedexpansion
set "folder=%~1"
if not defined folder set "folder=%cd%"
for /D %%q in ("%folder%\*") do (
echo test "%%q\%%~nxqDailyNotes.txt"
)
ENDLOCAL
Interesting exercise with a couple of twists.
my posted code will simply show 'test "fullfilename" '. Naturally, you could use copy nul "*fullfilename*"' to create an empty file (with>nulto suppress the creation-report) orecho.>"fullfilename"` to create a file containing just an empty line - or whatever.
The main magic is with the gymnastics in creating the filename. Since you are using for/d, the directoryname will appear in %%q. so the required filename is the name+extension part of that directoryname (you and I know it's actually not a filename but the outermost leafname of a directory tree - just don't tell cmd) so we use %%~nxq meaning the name and extension part of the "filename" in %%q (see for /?|more from the prompt for documentation). We then just tack the remainder of the required name on as a literal.
So - why the change to %%q?
Suppose we leave it as %%a. The filename would then be "%%~nxaDailyNotes.txt" and be interpreted as name,extension,attribute,drive of %%a since i is neither a modifier nor a participating metavariable. Changing the metavariable from %%a to %%q removes the misinterpretation.

Related

Pare down a variable to all before 1st space

BACKGROUND:
Have the following code. Lines 5 & 6 are the most important here:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0" || exit /B
move /Y "Folder2.jpg" "Folder.jpg"
This line 5 for %%I in (.) do set "FOLDER=%%~nxI"
This line 6 "%ProgramFiles(x86)%\gallery-dl\gallery-dl.exe" -d "U:\11Web\gallery-dl" --download-archive "%~dp0zzzGDB.sqlite3" "https://www.pixiv.net/en/users/%FOLDER%/illustrations"
if not errorlevel 1 if exist "zzzGDB.sqlite3" del "Folder.jpg"
popd
endlocal
In Windows Explorer I create a folder (for example) named "18604150". Any folders I create will have a folder name of varying lengths. The code above is in a .bat file within that folder. Upon executing the code, line 5 assigns folder name "18604150" to the variable and line 6 inserts/calls it as part of the hyperlink:
https://www.pixiv.net/en/users/%FOLDER%/illustrations
equates to
https://www.pixiv.net/en/users/18604150/illustrations
All is well.
PROBLEM:
I want to be able to ALWAYS name folders as with the aforementioned numerical string at the beginning but IN SOME CASES also manually append artist name and/or other details to the folder name. Problem is I need to do this without "breaking" the variable and making it unusable for the hyperlink. Folder names could take on many shapes but will always begin with an unbroken first string of numbers. Examples:
18604150 -59 Bob Marley-
4839 Dan the Man
19374759394727 Scooby Snack 43443
I need to pare the variable down to only the digits left of any first SPACE, when present.
18604150
4839
19374759394727
I'm guessing whatever the solution will likely have to be in Line 5, but I do not know what this would look like.
for %%I in (.) do set "FOLDER=%%~nxI"
A little trial and error got my answer. Thanks goes to https://www.dostips.com/DtTipsStringManipulation.php
#echo off
setlocal EnableExtensions DisableDelayedExpansion
pushd "%~dp0" || exit /B
move /Y "Folder2.jpg" "Folder.jpg"
for %%I in (.) do set "FOLDER=%%~nxI"
for /f "tokens=1 delims= " %%a in ("%FOLDER%") do set FOLDER=%%a
"%ProgramFiles(x86)%\gallery-dl\gallery-dl.exe" -d "U:\11Web\gallery-dl" --download-archive "%~dp0zzzGDB.sqlite3" "https://www.pixiv.net/en/users/%FOLDER%/illustrations"
if not errorlevel 1 if exist "zzzGDB.sqlite3" del "Folder.jpg"
popd
endlocal
pause

Batch file to read file names from CSV and rename files in a folder

I have a set of codes in a file, i want to rename the files in a folder with that code. Like first code for the first file then second code for the second file.
for /f "delims=" %%x in (code.csv) do call :rename "%%x"
pause
GOTO :EOF
:rename
REN "*.jpg" "a/%1.jpg"
This is what I have written but this is like running the first code for all the files and am getting a duplicate file name that exists or the file can not found error. Even though the files are being renames but it takes lots of time which I believe due to some unnecessary looping.
Any help to make it perfect will be appritiated
You need a way to read the directory and the csv in parallel. There is a trick to do that:
#ECHO OFF
setlocal enabledelayedexpansion
<code.csv (
for /f "delims=" %%x in ('dir /b *.jpg') do (
set "NewName="
set /p NewName=
if not defined NewName goto :eof
ECHO ren "%%x" "!NewName!"
)
)
NOTE: remove the ECHO command after verifying it does what you want to actually enable the ren command.
<code.csv ( ... ) provides one line after the other to the set /p within the for loop. Clear it before reading, so the NewName variable gets undefined, when there are no more names from the csv. Exit the for loop, when it is undefined (no more names).
The loop stops, when there are either no more files to be renamed or no more new names from the csv file.
See dir /? - especially the /o switch for how to sort the files (if needed) for names, dates or sizes.
Another possibility is to build an array of either the csv content or the files but I think that's an overkill for this task.

Trim Date from file name windows script

How do you trim the date from a text file. For example, I have multiple files like:
test_MX_abc_20091011.txt
test_MX_pqrdhdsu_20091011.txt
test_MX_xyieuz_20091011.txt
All files will have test_MX in common but the 3rd part will of different size.
I would like to change into:
test_MX_abc.txt
test_MX_pqrdhdsu.txt
test_MX_xyieuz.txt
I know how to change the file if name is like test_20091011.txt with the below code, But if name has more string along with date, how to do that?
for /F "tokens=1 delims=_" %%i in ("%%~na") do (
move /Y %%~fa %data_in%\%%i%%~xa >nul
)
Thanks in advance.
This rename operation can be done for example with:
#echo off
for /F "tokens=1-3* delims=_" %%A in ('dir /A-D /B test_MX_*.txt') do (
ren "%%A_%%B_%%C_%%D" "%%A_%%B_%%C.txt"
)
Each file name is separated into 4 strings assigned to loop variables A to D with using underscore as separator. The loop variable D takes everything of file name after third underscore.
Or also working for the 3 files:
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%F in ('dir /A-D /B test_MX_*.txt') do (
set "ActFileName=%%~nF"
set "NewFileName=!ActFileName:~0,-9!"
ren "%%~F" "!NewFileName!.txt"
)
endlocal
This solution assigns the name of a file without file extension and path to environment variable ActFileName. Next a new environment variable with name NewFileName is defined with name of active file without the last 9 characters (underscore and date string). This modified file name is used next in the rename operation.
Other solutions using commands for, set and ren can be found on Stack Overflow.
Search with the string
[batch-file] for set rename files
and more than 600 results are presented all using more or less something like above.
For details on the used commands, open a command prompt window, execute one after the other following commands and read output help.
dir /?
for /?
ren /?
set /?

Append folder name to file name and move file using DOS batch

There is folder structure like this:
rootfolder\subfolder1\file1.txt
rootfolder\subfolder1\fileA.txt
rootfolder\subfolderX\file2.txt
rootfolder\subfolderX\fileC.txt
Need to append the foldername to the filename and include current datetime. Then move the renamed file to the rootfolder i.e. like below:
rootfolder\subfolder1_file1_<datetime>.txt
rootfolder\subfolder1_fileA_<datetime>.txt
rootfolder\subfolderX_file2_<datetime>.txt
rootfolder\subfolderX_fileC_<datetime>.txt
Does anyone know script that can do this? Thanks a lot!
#ECHO OFF
SETLOCAL
SET "sourcedir=U:\sourcedir"
SET "datetime=%date:/=-%%time::=.%"
PUSHD "%sourcedir%"
FOR /f "delims=" %%a IN (
'dir /b /ad "%sourcedir%\*"'
) DO (
FOR /f "delims=" %%d IN ('dir /b/a-d ".\%%a\*.txt" 2^>nul') DO (
ECHO(move "%sourcedir%\%%a\%%d" "%sourcedir%\%%a_%%~nd_%datetime%%%~xd"
)
)
popd
GOTO :EOF
You would need to change the setting of sourcedir to suit your circumstances.
I've chosen to simply filter for .txt files - adjust the filemask to suit.
I don't know your date format or the date format you expect. You've not said whether you want the current date/time or the file's date/time to be inserted. current assumed.
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)

How can I sort images based on both date and parent folder?

I have been tasked with creating a monthly backup of photos, these need to be moved from where they are to somewhere else, sorted by date into folders, then burnt to disk in monthly lots.
In theory this should be simple, even though its a new process and we have roughly a year worth of photos, once its been done once we can just run it every month from now on.
So first thought is:
Copy from location "A" to location "B", sort into sub-folders based on created date "MONTH\YEAR", burn each folder to disk.
This is quite simple and would have been done now if that was the case, my issue is this:
All the photos are from other companies who we provide a service for, there are ~15 companies and each have their own folder. Inside each folder is 5 more folders, ONE of which has the images, others have config files database backups etc etc.
So as an example the structure is:
─Data
├─Company1
│ ├───IMAGES
│ ├───Other1
│ └───Other2
├─Company2
│ ├───IMAGES
│ ├───Other1
│ └───Other2
└─Company3
├───IMAGES
├───Other1
└───Other2
So within each "IMAGE" folder are the photos which aren't sorted by date. I need to copy only those folders to a structure which looks like this:
──Backups
├─01-15
│ ├───Company1
│ ├───Company2
│ └───Company3
├─02-15
│ ├───Company1
│ ├───Company2
│ └───Company3
└─03-15
├───Company1
├───Company2
└───Company3
That way I can simple burn each months folder to its own disk and in it all the images are sorted by company.
So create a folder with name of "MONTH-YEAR" then inside that, create folders for each company "Company1" "Company2" etc and then in each of those folders have the photos from that company and that month.
I have attempted to write this in batch to almost 0 success. Though I no longer have the code(deleted it in annoyance after it not working a few too many times :/ ), it used a lot of nested IF statements and variables being set to maintain the name of the parent folder of the parent folder etc etc then looping around to do the whole process on the next folder...
So long story short, I need some way to script the moving of images into folders based on date and the name of the folder two levels above it. Also if it could create the folders where its being copied to that would be great.
Even if someone could just provide some pointers of where to start in batch(or VBS), or some psuedo code which I can work off of I would GREATLY appreciate it.
Thank you very much,
this confused newbie!
These solutions assume directory listings show file time stamps as "MM/DD/YYYY HH:MM:SS PM". The code would have to be modified if the time stamp format is different for your locale.
I strongly recommend that you name your date folders using YYYY-MM format so that they sort chronologically. Also, you should not use 2 digit years - I lived through the Y2K nightmare - it isn't worth it.
If the dates come from each file's last modified date, then it is fairly easy - the ~t modifier provides the last modified date of the file:
%= Iterate company folders =%
for /d %%D in ("Data\*") do (
%= Iterate images under company folder =%
for %%F in ("%%D\IMAGES\*") do (
%= Parse last modified month and year for the file =%
for /f "delims=/ tokens=1,3" %%A in ("%%~tF") do (
%= Create the destination folder - ignore error if already exists =%
md "Backup\%%B-%%A\%%~nxD" 2>nul
%= Move the file =%
move "%%F" "Backup\%%B-%%A\%%~nxD" >nul
)
)
)
If you want the creation date instead, then it is a bit more complicated. I use the DIR /TC option to get the creation date, and the date and file name must be parsed from the DIR listing.
%= Iterate company folders =%
for /d %%A in ("Data\*") do (
%= Iterate images under company folder, parsing out created date and file name =%
for /f "tokens=1,4*" %%B in (
'dir /a-d /tc "%%A\images"^|findstr /rc:"^[^ ]"'
) do (
%= Parse the month and year from created date =%
for /f "delims=/ tokens=1,3" %%E in ("%%B") do (
%= Create the destination folder - ignore error if already exists =%
md "Backup\%%C-%%B\%%~nxA" 2>nul
%= Move the file =%
move "%%A\images\%%D" "Backup\%%C-%%B\%%~nxA" >nul
)
)
)
It is possible to use WMIC to get the creation date or last modified date in a locale agnostic manner. But the coding becomes quite complex, with lots of arcane tricks required to get the desired result in an efficient manner. The code below assumes you want the creation date. To use last modified date, simply change creationDate to lastModified.
#echo off
:: FOR loop variables must be expanded with delayed expansion off
:: otherwise values containing ! will be corrupted
setlocal disableDelayedExpansion
%= Iterate company folders =%
for /d %%D in ("Data\*") do (
%= Parse drive, company, and image path info =%
%= Enable delayed expansion to access variables set within loop =%
%= Escape \ in path for use with WMIC =%
set "drive=%%~dD"
set "company=%%~nxD"
set "imagePath=%%~pnxD"
setlocal enableDelayedExpansion
set "imagePath=!imagePath:\=\\!\\IMAGES\\"
%= Iterate images and creation dates for files under company folder using WMIC =%
%= Two FOR /F loops are used to eliminate trailing <CR> character from each line =%
%= The trailing <CR> is an odd artifact of conversion of WMIC unicode output =%
for /f "skip=1 delims=" %%A in (
'wmic datafile where "drive='!drive!' and path='!imagePath!'" get creationDate^, name 2^>nul'
) do for /f "tokens=1*" %%B in ("%%A") do (
%= Disable delayed expansion again to protect ! =%
setlocal disableDelayedExpansion
%= Save the date and file info. The file will have trailing spaces, but that =%
%= is OK because Windows ignores trailing spaces and dots in file names =%
set "date=%%B"
set "image=%%C"
%= Re-enable delayed expansion and parse out year and month to compute destination =%
setlocal enableDelayedExpansion
set "destination=Backup\!date:~0,4!-!date:~4,2!\!company!"
%= Create the destination folder - ignore error if already exists =%
md "!destination!" 2>nul
%= Move the file =%
move "!image!" "!destination!" >nul
%= Pop the setlocal stack to get back to state before inner loop started =%
endlocal
endlocal
)
%= Pop the setlocal stack to get back to state before outer loop started =%
endlocal
)
The job becomes much easier if you use my JREN.BAT utility, which can parse and format file timestamps in a locale agnostic manner. JREN.BAT is primarily used to rename files using regular expressions. But it has a list mode that allows you to transform a file name into nearly anything, without renaming, which can then be parsed with FOR /F.
The code below uses the creation date. Change created to modified if you want to use the last modified date instead.
#echo off
:: JREN does most of the work.
:: /LIST option lists the final "rename" value, without renaming anything
:: /P specifies root path
:: /S iterates all sub-folders
:: /PM determines which sub-folders to look at, /P: matches the root path
:: /J treats replacement value as JScript code
:: The "^.*" search matches the entire file name
:: The "ts({dt:'created',fmt:'{yyyy}-{mm} '})+path()" replacement
:: gets and formats the creation date using WMI
:: followed by the full path to the image file
:: The JREN output looks like: YYYY-MM fullPathToImage
for /f "tokens=1*" %%A in (
'jren "^.*" "ts({dt:'created',fmt:'{yyyy}-{mm} '})+path()" /list /j /s /p "Data" /pm "/P:\*\IMAGES"'
) do (
%= Get the company name from the fullImagePath =%
for %%C in ("%%B\..\..") do (
%= Create the destination folder - ignore error if already exists =%
md "Backup\%%A\%%~nxC" 2>nul
%= Move the file =%
move "%%B" "Backup\%%A\%%~nxC" >nul
)
)
So, instead of scraping the company name by the grandparent folder of the image, would it be acceptable to scrape it by the child of "Data"? This can be done with some string manipulation in a subroutine.
In a for loop, %%~tX has the last modified date of each file. Employing a couple of nested for loops to split that string by space, then by slashes can massage the date into MM-YYYY very easily. Edit: I looked up the date format for the New Zealand locale, and I think I've got the script configured correctly to scrape month and year for you. Give it a shot and see how it works. (If I were trying to make this locale-agnostic, I'd probably query wmic datafile for each file, but that'd be a bit of a job. Let me know if you need it.)
#echo off
setlocal enabledelayedexpansion
set "source=c:\Data"
set "destination=d:\Backup"
:: for every image file recursively in %source%
for /r "%source%" %%I in (*.jpg *.png *.gif *.bmp *.xcf *.psd) do (
rem :: get company name from directory 1 level within "Data"
call :getCompany company "%%~dpI"
rem :: get month-year from file last modified date
rem :: note: assumes ~t is in format of dd/mm/yy hh:mm
for /f %%a in ('echo %%~tI') do (
for /f "tokens=2,3 delims=/" %%x in ('echo %%a') do (
set "fdate=%%x-%%y"
)
)
set "folder=%destination%\!fdate!\!company!\"
if not exist "!folder!" md "!folder!"
<NUL set /P "=Copying %%~nxI to !fdate!\!company!\... "
>NUL copy "%%~fI" "!folder!"
echo Done.
)
goto :EOF
:getCompany <var_to_set> <path>
setlocal
set "company=%~2"
set "company=%company:*Data\=%"
set company=%company:\=&rem.%
endlocal & set "%~1=%company%"

Resources