Batch combine new elements into subtitle files - windows

I want to take a folder with several (15 in this first case) 'subtitle.srt' files (which, as I'm sure you're aware, are just text files with the extension ".srt" instead of ".txt") and modify each file in turn so that a new subtitle is added at the start of each file.
I want the new subtitle to be:-
0
00:00:00,001 --> 00:00:02,100
"Filename"
So, for example, if the first subtitle file in the folder is called "01. What Lies Beneath.srt" and it looks like this:-
1
00:00:02,120 --> 00:00:03,560
<font color="#FFFF00">Previously on Superman & Lois...</font>
2
00:00:03,560 --> 00:00:06,880
<font color="#00FFFF">I'm stepping down from active duty.</font>
<font color="#00FF00">You're going to be hard to replace.</font>
3
Etc., etc...
then after processing, I want it to look like this:-
0
00:00:00,001 --> 00:00:02,100
01. What Lies Beneath
1
00:00:02,120 --> 00:00:03,560
<font color="#FFFF00">Previously on Superman & Lois...</font>
2
00:00:03,560 --> 00:00:06,880
<font color="#00FFFF">I'm stepping down from active duty.</font>
<font color="#00FF00">You're going to be hard to replace.</font>
3
Etc., etc...
I'm rubbish at batch coding so I tried searching out possible ways to do it but nothing I tried worked!
Below are some attempts I made using different "routines" I found; each successive attempt separated (from last to first) by the PAUSE, EXIT commands:-
for %%a in (*.txt) do type append_ns0 >> %%a.srt
pause
exit
for %%a in (*.txt) do type append_ns0 >> %%a
for %%a in (*.txt) do type "%%~na" >> %%a
for %%a in (*.txt) do type append_spc >> %%a.srt
pause
exit
for %%I in (*.txt) do copy "C:\Users\wbcam\Desktop\G classroom\AddTitle.txt"+"%%~nI"+" "+"%%I" "%%~nI.srt"
pause
exit
for %X in (C:\Users\wbcam\Desktop\G classroom\Add Titles\*.txt) do type C:\Users\wbcam\Desktop\G classroom\AddTitles.txt >> %X
pause
exit
To use the COPY command I had to first rename the files from .srt to .txt (I'd rather NOT have to do that; I'm hoping someone can show me how to work on the ,srt files without any intermediate stages) and COPY also seemed to add a hex1A character to the end of the new file but, of course, it couldn't handle the insertion of the Filename (a text string) into the new file as it would only concatenate files not strings (if I, eventually, understood it's operation correctly, Doh!).
And attempts to use the ECHO or TYPE commands just seemed to overwrite everything in the original file leaving only:-
0
00:00:00,001 --> 00:00:02,100
and bugger all else!
Can anyone help out, please?

#ECHO OFF
SETLOCAL
rem The following setting for the source directoryis a name
rem that I use for testing and deliberately includes 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"
FOR /f "delims=" %%b IN (
'dir /b /a-d "%sourcedir%\*.srt" '
) DO (
(
ECHO 0
ECHO 00:00:00,001 --^> 00:00:02,100
ECHO "%%~nb"
ECHO.
TYPE "%sourcedir%\%%b"
)>"%sourcedir%\%%~nb.txt"
MOVE "%sourcedir%\%%~nb.txt" "%sourcedir%\%%b" >NUL
)
GOTO :EOF
Always verify against a test directory before applying to real data.
Perform a directory scan. assigning each filename that matches the mask to %%b.
Write the two required lines, a line containing the name part of the filename in quotes and an empty line to the output, then type the contents of the selected file. Note that the > character in the text needs to be escaped by a caret. The output of the echoes is gathered and redirected to a .txt file and the .txt file is then written over the original file. The 1 file(s) copied message is suppressed by the >nul.
If you prefer, you could replace the two echo lines that insert the fixed text with type somefilename where somefilename contains the fixed text required.
You could replace the move line for testing with
FC "%sourcedir%\%%~nb.txt" "%sourcedir%\%%b"
which will show the differences.
copy adds the control-z following an archaic convention that ^Z marked end-of-file for text files.
--- Addition in response to comment
for /? from the prompt generates documentation about the for command - in general, commandname /? generates documentation for any command, although some commands require -? or -h or --h or --help. Utility designers generally follow the same convention and the details depend on the platform for which the software was originally designed.
for /f ... ('command....') do ... interprets the command-output as though it was a file.
The dir command reports the filenames and subdirectorynames in a directory. By default, it produces a formatted report including filesize and last-update date, but has numerous options including /b to produces a "basic" report (names only, no sizes, headers, summary, dates ,etc.) and /a-d which suppresses directorynames. The /s option means 'and list subdirectories too'. It can also accept a filemask (or ambiguous filename) - which applies equally to directorynames. If the filename supplied contains a ? then this means any ONE character or * which means any number of any characters - any other characters are taken literally and will match regardless of case. Hence, *.srt means any number of any characters followed by .srtwhich should select all file/directorynames that end.srt. The filemask may be preceded by *directoryname\\* which means scan this directory- but *that* directoryname may **not** contain?or*`.
When for /f is supplied with a filename list in basic form, each filename in the list is assigned to the metavariable assigned (%%a in this example) in turn and the do statements are executed using the assigned value in the metavariable. Again, there are many ways of having for /f interpret the value-string that is assigned to the metavariable. Many, many examples of these on SO
In the days of CP/M, filesize was a number of 128-byte blocks. Since files were not often a multiple of 128 bytes long, convention was that a control-z marked the end-of-file. Backwards-compatibility is a big issue in computing as it's wasteful to revise existing systems to cater for a concept-revision. Hence, the control-Z convention is still recognised and observed for text files.

Related

How to remove leading whitespace from first line of text files using batch file in Windows?

I've got about 700 .tcx files (old GPS running data if you're interested...).
The first line is:
<?xml version="1.0" encoding="UTF-8"?>
That's 10 spaces at the start, which is preventing me from importing this data to Garmin Connect (I got a new Garmin watch).
So, I need to remove this whitespace from the front of this first line of 700 files. I'm trying to automate this process with a batch file (though given how long I've spent trying to do this, it would've been quicker to do it by hand...)
So far I've got:
#echo off
setlocal enabledelayedexpansion
for /F "tokens=1" %%A in (C:\[path]\[filename].tcx) do (
set line=%%A
echo !line:~1! >> C:\[path]\[filename].tcx
)
endlocal
Where [path] is the path to where the files are currently stored, and filename is the file I'm testing on. Once I've got it working I will replace [filename[ with *
Unfortunately what I've got isn't quite working at the moment:
Firstly, it is going through the whole file, not just the first line.
Secondly, on each line, it is not just deleting the leading whitespace, it is deleting everything upto and including the first character (which is a "<") and then also deleting everything after the next space that is comes across.
I know my attempt is kind of pathetic, but I'm hoping to learn!
#ECHO OFF
SETLOCAL
rem The following settings for the directories are names
rem that I use for testing and deliberately includes 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 %%e IN ("%sourcedir%\*.tcx") DO (
SET "first=y"
(
FOR /f "usebackqtokens=*" %%y IN ("%%e") DO IF DEFINED first SET "first="&ECHO %%y
FOR /f "usebackqskip=1delims=" %%y IN ("%%e") DO ECHO %%y
)>"%destdir%\%%~nxe"
)
GOTO :EOF
Always verify against a test directory before applying to real data.
Note that if the filename does not contain separators like spaces, then both usebackq and the quotes around %filename1% can be omitted.
This should accomplish the task. It simply reads the first line from each file, removing leading spaces (one of the default delims) and sends it to the output, resetting the first flag to prevent regurgitation of the remaining data.
Next step is to reproduce all but the first line.
All gathered together by enclosing the two fors in parentheses and redirecting.
Note that the source and destination directories must be different.

Trying to make a menu in a windows command prompt

I have a batch file that gets run by the user typing:
usercompile filename
usercompile is a batch file that does this:
copy /y %1.txt lib\incoming_file.txt
and then starts the compiler:
compiler.exe
The compiler has the "incoming_file" name hard-coded into linked source (this can't be chaged), so the current method is simply to copy the user file in and rename it to the known name and run the compiler.
I'd like to present the user with a list of files that are generated when a batch file is run, then the batch file would copy the selected file in, rename it (just like is done now).
So it would look like this:
Please choose a file to compile:
1) matthews_build
2) marks_build
3) lukes_build
and then the user would type 1 or 2 or 3 (in this case) and press enter. The batch file would copy that file to the known file name and launch the compiler. The one good thing is that the files that need to be listed all have a unique extension (.jal).
Any ideas?
I changed my approach and consider my previous answer a bad practice: re-listing the files with a second dir command unnecessarily reads the disk again, not to mention the rare but possible case if a file is added/removed between the 2 dir's and makes the whole thing unreliable.
Based on this brilliant solution I did a possible implementation with dynamic array:
#echo off
set /a counter=0
setlocal enabledelayedexpansion
FOR /f "delims=|" %%i IN ('dir /b /on "yourpath*.jal"') DO (
set /a counter+=1
rem echo !counter!^) %%~ni
set FileList[!counter!]=%%~ni & rem This is an array element, a dinamically created variable
)
rem Iterate through variables:
FOR /l %%i IN (1,1,!counter!) DO (
echo %%i^) !FileList[%%i]!
)
set /p option="Choose an option: "
echo !FileList[%option%]!
endlocal
This makes the file list available for any number of following commands.
One possible solution is to list all .jal files and give them an option number, store the result, and based on user input, look up the file based on the option number. As I know no way of storing such a result in memory (no array/hash table data type), only in a file, if a file can not be used, then the listing should be repeated in a deterministic way so that if we re-assign the option numbers, we get the same result. We can do it ensuring alphabetical ordering.
Here is one implementation:
BLOCK 1
setlocal enabledelayedexpansion
FOR /f "delims=|" %%i IN ('dir /b /on "yourpath\*.jal"') DO (
set /a counter+=1
echo !counter!^) %%~ni
)
endlocal
The nested dir command ensures alphabetical ordering (reference.)
A remark why I put a pipe (|) as a delimiter: if you don't define a delimiter, the default space will be used. If your file name contains space then it would be truncated. So I picked a character that is not valid in file names ensuring the whole file name is returned.
Now if you get a number from the user by this:
set /p option=Choose your option:
after this command (evaluating and possibly re-requesting the input) to do a lookup for the file you can repeat BLOCK 1 but replace the echo line with examining the option like this:
if !counter! == %option%
and put those commands in the if block to do whatever you want to do with the file (for debugging, put back the echo command).

Using a batch to sort through a complex of folders and sort any files with a specific string in their name to a specific directory?

So I have a collection of art from the internet; it is very large and spans an extreme amount of subdirectories under the main folder I keep it all under (entitled Uda). I've built up this collection over a period of about 4 years. In the most recent 2 years, I've been organising things I save by artist (most of this comes from the site DeviantArt if it matters). But I have 2 years' worth of files unsorted, all over the place and I'd like to sort them.
I figure this is an ideal time to practice some batch scripting, but... I've not the faintest idea where to start. Google hasn't been very helpful, it's too hard to explain what I want to do in one question, let alone find someone who has needed the same thing and been guided through it. Also, I'd honestly much prefer to pull apart and figure out an already-made script to understand it and learn from it (that's how I tend to learn best).
So can anyone help me? If you don't understand what I want to do:
I wish to make a script where I can input something (i.e. an artist's name) and have a folder made for it under a certain directory (no matter where the batch is being run from or the files drawn from) with the name of the term that was entered, and then all files under another directory with that term found and moved.
For the record, even if I weren't interested in batch scripting, I couldn't use Windows Explorer to search for them all then cut them because I disabled it (for personal reasons).
#ECHO OFF
SETLOCAL
:: Note that SPACES are significant in simple SET statements
:: Set relative or local root (start-point of subtree to scan)
:: Use normal then safemethod 1 then safemethod2 - all do the same thing
:: Note : from the prompt,
:: command /?
:: will generally show help...
SET relroot=c:\wherever
(SET relroot=c:\wherever)
SET "relroot=c:\wherever"
:: repeat for destination directory
SET "destdir=c:\destination"
::
:: Read Artist
:: Make sure ARTISTS has no existing value, then prompt for input
::
:again
(SET artist=)
SET /p artist="Artist ? "
::
:: Check for input, exit if none
:: Note :EOF is a special predefined label meaning "END OF FILE"
:: character case is generally insignificant
::
IF NOT DEFINED artist GOTO :eof
::
:: make a new directory
:: the 2>nul suppresses an error message like 'it already exists'
:: In quotes in case variables contain spaces
MD "%destdir%\%artist%" 2>nul
::
:: Now look for filenames containing the data entered
:: Note: here, the metavariable %%i IS Case-sensitive
:: >nul means 'don't show message like '1 file(s) moved'
FOR /f "delims=" %%i IN (
' dir /s /b /a-d "%relroot%\*%artist%*" '
) DO (
ECHO %%i
IF EXIST "%destdir%\%artist%\%%~nxi" (
ECHO Cannot MOVE "%%i" because "%destdir%\%artist%\%%~nxi" exists
) else (ECHO MOVE "%%i" "%destdir%\%artist%\%%~nxi" >nul)
)
GOTO again
Well, here's a starter script - assuming that artists' names are in the filename.
Most of the documentation is in-line.
Note that the ::... form of documentation is actually a broken-label and is inadvisable within loops and parenthesised code generally - use REM there. It is however easier to type and less intrusive
The FOR loop needs a little explanation: much of it can be deciphered with a bit of persistence from the documentation
for /?
from the prompt. But the heads-up is:
for /f reads a "file" line-by-line and applies each successive line to the metavariable after being tokenised between delimiters. You can specify the tokens by number counting from 1 and the delimiters are any characters appearing between the delims= and the closing quote. Default delimiters are [space],[tab],[comma],[semicolon] and default tokens is 1. "delims=" specifies that there are no delimiters, so the entire line is applied to the metavariable.
It's possible to use this facility on a data line like Wed. 07/11/2012 by using FOR/f "tokens=2,3,4delims=/ " %%i in... to apply 07 to %%i, 11 to %%j and 2012 to %%k - the tokens are Wed.,07,11 and 2012 when the line is tokenised using [either space or /] and the 2nd token is applied to the loop metavariable %%i, the third to %%j and so on through the list of token numbers. The special token "*" means 'the rest of the line following the highest-number token nominated'
AND.. a single-quoted "filename" is the output of a command. dir /s /b /a-d "%relroot%\*%artist%*" is the directorylist in /b basic form (filenames only) /s scan subdirectories /a-d but don't mention the war directorynames starting at %relroot% and having %artist% somewhere in the filename - all quoted in case spaces are present.
I wont write it for you but, but here is a list of roughly the things you have to achieve. Try looking for each of those and then combine them
input a name
create a directory with this name
find the files with this name
move found files to the directory
if you post code of what you are trying i'll gladly help you.

Batch file for loop string replacement

I have a batch file that take a directory path as a parameter.
In that file folder, there are any number of .ai.pdf or .pdf files that I need to convert to jpg's. The conversion is not my issue (I am using imageMagick) , but lopping off the full extension is.
I need to be able to either take off the full .ai.pdf (7 characters) or .pdf (4 characters) from the file name and replace it with .jpg I cannot use just ~n in the for loop because it will not take off the .ai in an instance with there is an .ai.pdf (results in file name.ai where I need just the file name)
There are quite a few posts on StackOverFlow about this
StackOverFlow Example
but no matter what I attempt to try, I get an error when truncating the appropriate amount of extension off of the file name.
Here is my code. This is the first major batch file I have ever created, so I am open to anything, other than installing more programs to do the work.
The thing that kills me, is I had this working and in the shuffle from one server to another and a week of vacation, the working code got....misplaced.
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set dir1=%1
echo recieved !dir1!
for /R %dir1% %%a in (*.pdf) DO (
echo file found !a!
set b=th_%%~nxa
if x%b:ai.pdf=%==x%b% set b=%%~dpa!b:~0,-7!
if not x%b:ai.pdf=%==x%b% set b=%%~dpa!b:~0,-4!
REM convert -density 64 "%%a" +matte -resize 15%% "!b!.jpg"
#echo !b! converted
)
ENDLOCAL
the file tells me that %~dpa!b:~0,-7! is an invalid substitution
Any ideas? Thanks for the help!
A few things first:
!a! and %%a are two different variables.
if x%b:ai.pdf=%==x%b% does not mean what you think it does. That will only be true when %b% does NOT contain .ai.pdf.
Again, if not x%b:ai.pdf=%==x%b% does not mean what you think. This is true when %b% DOES contain .ai.pdf.
There is no need to do any verification and cutting, just search and replace. ( That is what the %y:x=z% notation does, in this example it replaces every x within %y% with a z.) Let search and replace do the verification. It will only replace what matches the search. That will speed up the your batch file.
Lastly, since you are inside a () code block you will need to use the delayed Expansion turned on with your setlocal statement. This is because everything inside a code block is treated as if it were on a single line. That means that if you change a variable inside a code block, you will not be able to see the new value using the % notation. Instead you need to replace the %'s with !'s. For instance...
setlocal enableDelayedExpansion
set x=Hello
(
set x=Goodbye
echo I don't know why you say "!x!", I say "%x%".
)
...will give you the old Beatles lyric...
I don't know why you say "Goodbye", I say "Hello".
Anyway, on to your answer:
#echo off
SETLOCAL ENABLEDELAYEDEXPANSION
set dir1=%1
echo recieved !dir1!
for /R %dir1% %%a in (*.pdf) DO (
:: Adding a colon to the end of the filename allows the extension to be ID'd
: without explicitly looking at it with an IF statement, while simultaneously
:: avoiding similar looking character groupings inside the filename.
set b=th_%%~nxa:
:: No need to check for case, the substitution will do that for you.
set b=!b:.ai.pdf:=.jpg!
set b=!b:.pdf:=.jpg!
REM convert -density 64 "%%a" +matte -resize 15%% "!b!"
echo %%a converted into !b!
)
ENDLOCAL
The drawback is that both the files...
X.ai.pdf
X.pdf
...will be translated into th_X.jpg, creating the possibility of duplicate filenames for two different files.
But that's intrinsic to your concept of treating both types of filenames the same. If you don't have a method for avoiding this sort of duplication it might not be a bad idea to leave the .ai on the file, thereby creating two files: th_X.jpg and th_X.ai.jpg, eliminating the possibility of duplicate filenames.
Hm... would this work for you:
for /R %F in (*.pdf) do #for %G in ("%~nF") do #echo %~nxF ==^> %~nG.jpg
(as executed directly from cmd, if run from batch, replace % with %%).
This has a peculiar effect of changing the case of a file to case of a directory if there exists one with the same name as base name of your file (file.pdf will become FILE.jpg if you happen to have a subdirectory called FILE), but that's it (I think).
This also assumes your base names differ (so no file.ai.pdf and file.pdf in same directory)

How to rename and add incrementing number suffix on multiple files in Batch Script?

I have 500 files coming in and I need to first check if any file(s) exist then rename all of them regardless of what their filename is (the files are named in a different language).
No need to process them in any order.
Rename:
1. “¦X¼d¬f-20110703-¦+¦dñHÑ-ª-¦=¬¦.xls”
2. “¦X¼d¬f-20110707-¦+¡¦-+¡8.xls”
3. “¦X¼d¬f-20110707-¦+¡¦ñj¦«.xls”
4. “¦X¼d¬f-20110708-¦+¡¦¬M¼n.xls”
5. “¦X¼d¬f-20110713-¦d¼O¼n¦hÑP.xls”
.
.
.
500
To:
“TWN_CH_INV_VISIT_FORM_01.xls”
“TWN_CH_INV_VISIT_FORM_02.xls”
“TWN_CH_INV_VISIT_FORM_03.xls”
“TWN_CH_INV_VISIT_FORM_04.xls”
“TWN_CH_INV_VISIT_FORM_05.xls”
.
.
.
“TWN_CH_INV_VISIT_FORM_500.xls”
Hope you could help me on this one. I’ve been trying to do this for weeks.
a simple FOR with a count (SET /A) should do what you need.
setlocal enabledelayedexpansion
SET /A COUNT=0
FOR %%A IN (*.xls) DO (
SET /A COUNT+=1
REN "%%A" "TWN_CH_INV_VIST_FORM_!COUNT!.xls"
)
See HELP FOR and HELP SET
This is a deceptively difficult question to solve.
The 5 year old PA answer has a few problems.
1) The FOR loop begins iterating without buffering the entire directory tree, so it has the potential to rename a file that has already been renamed. I believe that is why the 7 file is missing within r0mmel's comment.
2) Delayed expansion occurs after for variables are expanded, so the file name will be corrupted and the rename will fail if the name contains a ! character.
3) A rename can fail if there already exists a TWN_CH_INV_VIST_FORM_n.xls file with the same number.
At first I thought I could solve the problem using the following:
#echo off
for /f "delims=: tokens=1*" %%A in (
'dir /b *.xls ^| findstr /n "^"'
) do ren "%%B" "TWN_CH_INV_VIST_FORM_%%A.xls.new"
ren *.txt.new *.
I use DIR /B to list the files, and pipe that result to FINDSTR to prefix each file name with a line number, followed by a colon.
I then use FOR /F to iterate and parse the results into the number and the file name. FOR /F buffers the entire result before iterating, so I don't need to worry about renaming the same file twice.
I first give the renamed files a .xls.new "extension", just in case your directory already has files that meet the TWN_CH_INV_VIST_FORM_n.xls pattern. You don't want any name collisions. The final REN command then simply removes the .new extension to leave the desired .xls.
BUT, I just noticed that the original file names have lots of weird characters that could involve unicode that is not in the current code page. FOR /F does not play well with unicode.
There is one other minor issue in that the above does not pad the number to a fixed width. (this could have been solved easily enough)
So at this point it is time to break out my JREN.BAT regular expression renaming utility. It is pure script (hybrid batch / JScript) that runs natively on any Windows machine from XP onward. It has a built in facility to incorporate a fixed width incrementing number in the new name, and it works fine with unicode. I still temporarily give the new name the ".xls.new" extension to avoid any name collisions.
#echo off
call jren "^.*" "'TWN_CH_INV_VIST_FORM_'+$n+'.xls.new'" /j /npad 3 /fm *.xls
ren *.xls.new *.
I chose to pad the incrementing number to 3 digits instead of 2 because the OP said there could be 500 files.
Full documentation for JREN.BAT is available from the command line via jren /?, or jren /?? if you want paged output.

Resources