Batch trim characters at the EOL - batch-file

i would like to create a batch file that goes through txt files in a directory and every line that has #EXTINF in it, remove the last 15 characters..
basically if it is possible, i would like to trim the last 15-20 characters from any lines that is longer than a certain number. for some reason i have a software that if the line is too long, it will screw up the data.
thanks

See How can you find and replace text in a file using the Windows command-line environment? for various options to modify text files using Windows batch.
The following simple code uses REPL.BAT to truncate long lines that begin with #extinf (case insensitive) at 600 characters. Lines that are less than 600 characters are preserved in their entirety.
type test.txt|repl.bat "^(#extinf.{593}).*$" "$1" I>test.txt.new
move /y test.txt.new test.txt >nul

User231429 wrote: "i need the script to go through all files in a directory, and each line that starts with #extinf, remove XX number of characters from the end."
The Batch file below do precisely that:
#echo off
setlocal EnableDelayedExpansion
for %%f in (*.txt) do (
(for /F "usebackq delims=" %%a in ("%%f") do (
set "line=%%a"
if "!line:~0,7!" equ "#extinf" set "line=!line:~0,-XX!"
echo !line!
)) > "%%~Nf.new"
)
REM del *.txt
REM ren *.new *.txt
Note that you must replace XX by a number in the long if command.
Test this program and check the result in *.NEW files. If the result is correct, remove REM part from two last lines.
This program remove exclamation marks from the file. This detail may be fixed, if required.

Related

batch removing padding white space

I have a batch file that will read values from a .ini file line by line, and use these variables to do other steps.
config.ini
Folder=Z:\task\first task\archive\
FileName=aFileName.xlsx
break
Then in my batch file i read the lines like the following and copy it to somewhere else like the following: job.bat
for /f "tokens=1,2 delims==" %%a in (.\config.ini) do (
if %%a==Folder set Folder=%%b
if %%a==Format set Format=%%b
if %%a==break (
call :copyFile
)
)
GOTO :EOF
:copyFile
xcopy %Folder%%Filename% D:\abc\ /f /y
GOTO :EOF
so the problem is at %Folder%%Filename%
for some reason, there is a space between the folder path and File name so it turns out to be
Z:\task\first task\archive\ aFileName.xlsx
I have tried to echo the variable after reading from file line by line and do echo "%Folder%" and i can see there are white space at the end of the variable. is there anyways to trim ONLY the end of the variable? I have tried some suggestions online, but it seems like it would also remove the white space within the variable, as you can see I do have a white space in the folder variable
Also, is there a way to exclude some of the charaters during string replacement. eg:
set filename=name_mm.txt
call set replaceName=%filename:mm=01%
this will replace the character mm to 01 in result of name_01.txt
but in another case, i got a filename that also have mm inside eg:
set filename=communicate_mm.txt
in this case, is there a way to ONLY replace the mm add the end? I know i could've replace the string _mm instead of mm, but there are other cases that the file name format like yyyymmdd.
:copyFile
if "%folder:~-1%" equ " " set "folder=%folder:~0,-1"&goto copyfile
xcopy %Folder%%Filename% D:\abc\ /f /y
would probably cure the spaces-at the-end problem.
You really shouldn't ask two questions in one - at the price charged per question, it's not expensive.
But for the second question, why no replace _mm instead of mm?
But if you want the last 3 characters, then
%varname:~-3%
and all but the last 3
%varname:~0,-3%
which is documented in the set instruction - try set /? from the prompt.

How to remove digits from beginning of filename?

I need to rename a filename like this 7612372 filename 50x50.jpg into this filename 50x50.jpg, removing all digits at the beginning of the filename.
The number of digit can be variable.
I need to integrate this into an existing batch file run from the Windows command prompt.
If the format of the filename would be the same for all the files in the folder, then you can try:
#echo off
for /F "delims=" %%A IN ('dir /b /A-D') do (
for /F "tokens=2-3" %%B IN ("%%A") do (
ren "%%~fA" "%%B %%C"
)
)
This is the shortest way, but not the most accurate one. It is unsecure, because if the filename contains spaces, the file will be rename incorrectly. I suggest the following code for the task:
#echo off
setlocal EnableDelayedExpansion
for /F "delims=" %%A IN ('dir /b /A-D') do (
set filename=%%A
for /F "tokens=1" %%B IN ("%%A") do (
ren "%%~fA" "!filename:%%B =!"
)
)
which is more accurate and renames all files correctly only if they have the format mentioned in the beginning.
#echo off turns command-echoing off.
setlocal EnableDelayedExpansion enables delayed expansion. We use it only here, as we have to access variables inside a for loop which is a code block. You must use delayed expansion always inside these code blocks.
Now we make a for loop to parse the output (/F) of the dir /b /A-D command which lists all items in current working directory (%cd%), excluding directories (/A-D).
We need to set a variable here with the filename. We could use the variable name of the loop (%%A), but variables have an advantage: %var:search=replace%, or even !var:search=replace! which we need here.
Now we make another for loop to parse a string (/F): the filename (%%A). We need to access the first token to substract it later. We don't really need to specify it here, but it is good to make it clearer.
We rename files now: %%~fA is the full path where filename currently processed is and !filename:%%B =! means to take filename environment variable, search for string "%%B " (first part of filename [digits] and a space) and replace it with an empty string; actually nothing!
An easier solution is to use
all digits and space as delims and
tokens=*
:: Q:\Test\2019\01\06\SO_54054587.cmd
for /F "delims=" %%A in (
'dir "* *" /A-D-H /B 2^>nul'
) do for /F "tokens=* delims=0123456789 " %%B in (
"%%A"
) do ren "%%A" "%%B"
this will remove all leading delimiters while not splitting the remainder of the file name.
Like the other answers this will not account for the shorted file name already being present.
Your question is not specific enough for us to provide a solution, you really need to provide the section of code into which you wish this to be integrated.
This one expects only one file, as in your question, and that file must be named in the format you've indicated, i.e. the required part is separated from the non-required part by a space:
#Set "name=7612372 filename 50x50.jpg"
#Ren "%name%" "%name:* =%"
[Edit /]
I have noted from your comments that you were indeed looking to parse several files and those files did not match the naming scheme you provided in your question.
Here therefore is an updated potential solution based on those changed parameters.
#For %%A In (*.*) Do #For /F "Tokens=* Delims=0123456789 " %%B In ("%%A") Do #Ren "%%~A" "%%B"
Apologies to LotPings, who I've noticed has posted a very similar method/solution
It's very simple with the basic DOS command rename.
7612372 filename 50x50.jpg
If this is your sample file in the folder, it contains 7 digits and 1 blank space. Totally 8 characters.
We can do this by simply running this command on the particular folder
rename "*.mp3" "////////*.mp3"
each / represents a character you want to remove. That's it.
I suggest following batch code for this task:
#echo off
for /F "delims=" %%A in ('dir "* *" /A-D-H /B 2^>nul') do for /F "tokens=1*" %%B in ("%%A") do ren "%%A" "%%C"
pause
The command FOR runs with cmd.exe /C (more precise %ComSpec% /C) in a separate command process in background the command line:
dir "* *" /A-D-H /B 2>nul
DIR outputs to handle STDOUT of this background command process
just the names of all non-hidden files because of option /A-D-H (attribute not directory and not hidden)
in bare format because of option /B without file path
matching the wildcard pattern * * which matches any file name with at least one space inside
in current directory which can but must not be the directory of the batch file.
DIR would output an error message to handle STDERR if it can't find any directory entry matching these criteria. This error message is redirected to device NUL to suppress it.
Read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
FOR captures all lines output to handle STDOUT of started command process and processes those lines after started cmd.exe terminated itself. It is very important for this file renaming task that FOR runs on a list of file names captured before doing the file renames as otherwise the directory entries would change while FOR is accessing them. For that reason for can't be used directly in this case because of for would process the list of * * directory entries while this list changes on each successful file rename. The result would be files not renamed or renamed multiple times or even an endless running loop depending on file system (NTFS or a FAT file system like FAT32 or ExFAT).
FOR with option /F ignores empty lines which do not occur here. FOR ignores also lines starting with a semicolon because of end of line option eol=; is the default. But all lines output by DIR should start with a number and for that reason the default end of line definition can be kept for this task.
FOR with option /F splits up a line by default to substrings using normal space and horizontal tab as delimiters and assigns just first space/tab separated string to specified loop variable. This line splitting behavior is not wanted here in outer FOR loop because loop variable A should hold complete file name with all spaces. Therefore delims= is used to define an empty list of delimiters to disable the line splitting behavior. Safer would be "delims= eol=" which defines also no end of line character.
The file name assigned to loop variable A is referenced with %%A as string in inner FOR loop which splits up the file name into two substrings (tokens). The first substring is the number assigned to specified loop variable B. The second substring after first sequence of spaces (tabs not possible in a file name) is assigned without any further splitting to next loop variable C according to ASCII table. In other words on file name 7612372 filename 50x50.jpg loop variable B holds 7612372 and filename 50x50.jpg is assigned to loop variable C.
The command REN renames the file by referencing complete file name as assigned to loop variable A to the part after first sequence of spaces as assigned to loop variable C.
The command PAUSE at end is added to see the error message output by command REN if renaming a file failed. There is nothing output except the prompt by PAUSE on all files could be renamed successfully.
The batch code can be enhanced further by using FINDSTR as filter to make sure that a file to rename starts really with one or more digits up to first space by using this code:
#echo off
for /F "delims=" %%A in ('dir "* *" /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /R /C:"^[0123456789][0123456789]* "') do for /F "tokens=1*" %%B in ("%%A") do ren "%%A" "%%C"
pause
One more variant for renaming a file with name 03T30 NAME T ALL 40X40X2 - Copy.JPG to T30 NAME T ALL 40X40X2 - Copy.JPG:
#echo off
for /F "delims=" %%A in ('dir /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /R "^[0123456789][0123456789]*"') do for /F "tokens=* delims=0123456789 " %%B in ("%%A") do ren "%%A" "%%B"
pause
DIR outputs the names of all non-hidden files in current directory. This output is redirected as input for FINDSTR which checks if the file name starts with one or more digits. Only those file names are output to STDOUT of background command process to be processed next by FOR.
The inner FOR interprets all digits and space character as string delimiters because of delims=0123456789  and assigns everything after first sequence of digits or spaces to loop variable B because of tokens=*. So loop variable B holds filename 50x50.jpg with 7612372 filename 50x50.jpg assigned to A and T30 NAME T ALL 40X40X2 - Copy.JPG for file name 03T30 NAME T ALL 40X40X2 - Copy.JPG.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
dir /?
echo /?
findstr /?
for /?
pause /?
ren /?
PS: I recommend the usage of the shareware file manager Total Commander which has a built-in multi-rename tool for renaming files and folders for people with no coding experience. Download, install and start Total Commander, navigate to the folder containing all these files, press Ctrl+A to select the files, press Ctrl+M to open multi-rename tool window and the rest is self-explaining. If you need nevertheless help, press key F1 to open the help page for multi-rename tool.

Batch file rename using regex to match 4-digit year

In a windows batch file, I would like to rename files containing a 4-digit year (ex: "1999") in the filename by simply wrapping the year string in parentheses. Example:
home video 1998.avi
home vid 1987.mov
home_video (2002).avi
would become
home video (1998).avi
home vid (1987).mov
home_video (2002).avi
Notice that if it's already wrapped in parentheses, I'd prefer not to double them up.
So far, I have only been able to match the file names containing a year string with the following code:
#echo off
REM Match file names with 4-digit year
setlocal enableDelayedExpansion
for /f "tokens=1* delims=" %%A in (
'dir /B "*"^|findstr "[1-2][0-9][0-9][0-9]" '
) do #echo %%A
pause
REM Now what?
So I can output a list of matching file names, but from there I do not know how to target the grouped characters that findstr matched in order to parse the full file name into the 3 chunks I believe I would need: the substring preceding the matched group, the group itself, and the substring following the group.
Is this possible in a batch file?
I use since more than 20 years Total Commander (shareware) for file/folder renaming tasks which makes it possible with its built-in multi-rename tool to easily rename files and folders with just a few clicks on which the results can be viewed before really running the multi-rename and which even supports undo after having done the multi-rename. Well, in real I use Total Commander for nearly all file management tasks.
But it was interesting to develop the code for this very special file renaming task with all the limitations Windows command processor has because of not being designed for such tasks.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir /A-D-H /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /R /C:"19[89][0123456789]" /C:"20[012][0123456789]"') do call :RenameFile "%%I"
endlocal
goto :EOF
:RenameFile
set "FileName=%~n1"
setlocal EnableDelayedExpansion
set "Year=1980"
:YearLoop
set "NewName=!FileName:%Year%=(%Year%)!"
if "!NewName!" == "!FileName!" (
if %Year% == 2029 goto ExitSub
set /A Year+=1
goto YearLoop
)
if "!FileName:(%Year%)=!" == "!FileName!" ren "%~1" "!NewName!%~x1"
:ExitSub
endlocal
goto :EOF
FOR executes the following command line with using a separate command process started in background with cmd.exe /C:
dir /A-D-H /B 2>nul | C:\Windows\System32\findstr.exe /R /C:"19[89][0123456789]" /C:"20[012][0123456789]"
DIR outputs with the used options all names of non-hidden files in current directory with just file name + extension and without file path. An error message output in case of current directory does not contain any non-hidden file is suppressed by redirecting it from handle STDERR to device NUL with 2>nul.
The file names output by DIR are redirected with | to handle STDIN of command FINDSTR which searches case-sensitive with two regular expression interpreted search strings for four digits in range 1980 to 1999 or in range 2000 to 2029. There is no check made if a match of a four digit number is part of a larger number like 12000 or 19975. And there is no check made if there are already round brackets around the four digit number.
FINDSTR interprets also ¹, ², ³ as digit on using [0-9] which is the reason for using [0123456789] to really match only any of those 10 digit characters. Please read for more details about FINDSTR the articles SS64 - FINDSTR and What are the undocumented features and limitations of the Windows FINDSTR command?
FINDSTR outputs all file names containing four digits in range 1980 to 2029 to handle STDOUT of background command process.
Please read the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on FOR command line to be interpreted as literal characters when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
FOR captures those lines and processes them line by line. The default for option eol= (end of line) is a semicolon and so FOR would ignore all file names starting with a semicolon. For that reason eol=| is specified because a vertical bar cannot be used in a file name and so all captured file names are processed by FOR.
FOR would split up each file name on spaces/tabs by default and assigns only the first substring (token) to specified loop variable I. This splitting behavior is disabled by using delims= which defines an empty list of delimiters. tokens=* is not the same as this results in removing leading spaces from the file names. File names can start with one or more spaces although this is very unusual.
A file name can contain also exclamation marks ! which must be also taken into account on using delayed environment variable expansion. Each file name is passed to a subroutine for further processing it.
A loop is used to replace all occurrences of year assigned to loop variable Year by the year in round brackets until new file name is different to current file name because the substitution was indeed positive for searched string. for /L %%J in (1980,1,2029) do ... was not used as this loop can't be exited once having found the right year in file name.
After having found the year in file name it is checked if this year is not already embedded in parentheses to avoid renaming a file with name home vid (1987).mov to home vid ((1987)).mov. So for example home video 1998.avi is renamed finally to home video (1998).avi.
A file name containing two numbers with four or more digits is also not processed correct as this code can't find out what is the year in such a file name.
This batch code is not really fast, but it should work with the listed limitations.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
dir /?
echo /?
endlocal /?
findstr /?
goto /?
if /?
ren /?
set /?
setlocal /?
See also Where does GOTO :EOF return to?
PS: File names with ( or ) in name make processing them with a batch file very often more difficult as in this case the file name must be always enclosed in double quotes like for file names containing a space character because of ( and ) have also a special meaning for Windows command processor cmd.exe as it can be seen on code above. See also How does the Windows Command Interpreter (CMD.EXE) parse scripts?

How to get just the first line of a text file written into a new text file using a batch file?

Okay I have several lines in a text file. I want to get the first line and save it in another file. For example this is the text file:
put returns between paragraphs
for linebreak add 2 spaces at end
for linebreak add 2 spaces at end2
for linebreak add 2 spaces at end3
I want put returns between paragraphs to be saved into another file.
I used
for /f "tokens=" %%A in ('findstr /r "^[0-9][0-9]*$" <"C:\Users\Sherlock\Desktop\AbcImport\123.txt"') do echo 123>>1234.txt
pause
But it doesn't work at all.
How to get just the first line of a text file written into a new text file using a batch file?
Option 1 - SET /P : This is the simplest and fastest pure batch solution, provided the line does not exceed 1021 bytes, and it does not end with control characters that must be preserved. The size of the file does not matter - it will always read and write the first line very quickly.
#echo off
setlocal enableDelayedExpansion
set "ln="
<"input.txt" set /p "ln="
>"output.txt" (echo(!ln!)
Option 2 - FOR /F : This will work with lines up to ~8191 bytes long, but it can be slow if the file is really large because the FOR /F loop must read the entire file before it processes the first line. This solution is basically the same as the Mofi answer, except it disables the EOL option, so it never ignores the first line, regardless what the first character is. It does have a limitation that it will skip empty lines, so technically it does not give the correct result if the first line is empty:
#echo off
for /f usebackq^ delims^=^ eol^= %%A in ("input.txt") do echo(%%A>"output.txt"&goto :break
:break
There is a way to preserve the first line if it is empty using pure batch, but I would not bother. I would move on to ...
Option 3 - JREPL.BAT, or some other non-batch solution : Batch is quite poor at manipulating text files. You are much better off using some other scripting language like VBScript, JScript, or Powershell. Or a Windows port of any number of unix utilities.
I would use JREPL.BAT - a hybrid JScrpit/batch regular expression text processing utility that runs natively on any Windows machine from XP onward. It is way overkill for such a simple task, but it is an extremely handy, powerful, and efficient tool to have in your arsenal. Once you have it, then it can be used for many text processing tasks. Full documentation is embedded within the script.
jrepl "^.*" "$&" /jendln "quit=true" /f "input.txt" /o "output.txt"
Use CALL JREPL if you put the command within a batch script.
Here is the batch code to write just first non blank/empty line of a text file into another text file.
#echo off
for /F "usebackq delims=" %%I in ("InputTextFile.txt") do (
echo %%I>"OutputTextFile.txt"
goto ContinueAfterLoop
)
:ContinueAfterLoop
InputTextFile.txt is the file in current directory containing the first line to copy.
OutputTextFile.txt is the file created in current directory with first line from input file copied into this output file.
The command GOTO is used to exit the loop after first line is processed and continue the batch file below the loop.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
for /?
goto /?
Read also the Microsoft article about Using Command Redirection Operators.
You can use use this command:
SetLocal EnableDelayedExpansion
for /f "tokens=* delims=;" %%m in ("C:\Users\Sherlock\Desktop\AbcImport\123.txt") do (
set /p FirstLine=<%%m
echo !FirstLine!>>1234.txt
)
and for multiple file:
SetLocal EnableDelayedExpansion
for %%a in ("*") do (
for /f "tokens=* delims=;" %%m in ("%%a") do (
set /p FirstLine=<%%m
echo !FirstLine!>>1234.txt
)
)
rem Get the first line of a text file:
set /P "line=" < "C:\Users\Sherlock\Desktop\AbcImport\123.txt"
rem Write it into a new text file:
echo %line%> 1234.txt

Windows Command batch script to add filename to end of each row in a merged text file

I a new to windows command line scripts.
I have a batch file which i use to merge multiple text files into one. However i want to be able to also add the name of the text file the row comes from to the end of each row in the merged file.
This is the script i am currently working with:
#ECHO OFF
ECHO Creating %1...
FOR /F "usebackq tokens=1" %%G IN (`DIR /B "C:\My Documents\Data\*.txt"`) DO
(
ECHO Adding %%G
ECHO. >> Output.txt
TYPE %%G >> Output.txt
)
Now i know that to get the filename into the output file i need to use:
ECHO %%G >> Output.txt
However i'm not sure how i would add this to the current script so it adds the filename to each row and I have had no luck with finding any examples.
There is a simple two liner that works from the command line if you are willing to prefix each line with the file name instead of putting the file name at the end. This solution is extremely fast.
cd "C:\My Documents\Data"
findstr "^" *.txt >output.log
Each line will have the format of filename:line content
It is important that your output file use a different extension than the files you are merging. Otherwise you run the risk of the command processing its own output!
The other option is to make sure the output goes to a different folder, perhaps the parent folder:
cd "C:\My Documents\Data"
findstr "^" *.txt >..\output.txt
Or, if you are willing to include the full path to each file in your output, then make sure current directory is not the same as your source, and use
findstr "^" "C:\My Documents\Data\*.txt" >output.txt
The only drawback to the above solution is that problems can arise if the last line of a text file does not end with a newline character. This will cause the first line of the next file to be appended to the last line of the prior file. Something like: FILENAME1:last line without newlineFILENAME2:first line of next file
A simple script can append a newline to files that are missing the newline on the last line. Then the files can be safely merged with the filename prefix on each line:
#echo off
if "%~1" equ ":FindFiles" goto :FindFiles
cd "C:\My Documents\Data"
:: Append newline to text files that are missing newline on last line
for /f "eol=: delims=" %%F in ('"%~f0" :FindFiles') do echo(>>"%%F"
:: Merge the text files and prefix each line with file name
findstr "^" *.txt >output.log
exit /b
:FindFiles
setlocal enableDelayedExpansion
:: Define LF to contain a newline character
set lf=^
:: The above 2 blank lines are critical - do not remove
:: List files that are missing newline on last line
findstr /vm "!lf!" *.txt
You'll need to add each line in the file individually:
#ECHO OFF
ECHO Creating %1...
SET "sourcedir=c:\sourcedir"
FOR /F "delims=" %%G IN ('DIR /B /a-d "%sourcedir%\*.txt"') DO (
ECHO Adding %%G
ECHO. >> Output.txt
for /f "usebackq tokens=*" %%a in ("%sourcedir%\%%~G") do (
Echo %%a - %%G >> Output.txt
)
)
Note in the second last line, the file name and the line is seperated by a -, you can replace this with whatever (don't forget to check for escaping characters) or can get rid of this if you want.
I'm sure that will work, but if it doesn't, tell me the Error message and I can fix it for you.
Mona
---- [edit:pw]
Close - major problem was the ( on the FOR ... %%G line was on the line following the DO - must be on the same line as the DO.
Added /a-d to the DIR to prevent subdirectory names matching
changed "usebackq tokens=1" to use conventional quotes and allow spaces in filenames
assigned target directory name to sourcedir variable and included %sourcedir% in both FOR statements to allow execution from anywhere, otherwise the filenames found in C:\My Doc.... would be searched-for in the current directory for replication into the output.
OP needs to change value assigned to sourcedir to C:\My
Documents\Data

Resources