I want to make a generic batch script which will read a schema file which will contain the various width's/column length's of the fixed width flat file source and finally create a target csv file based on the column length.
Example:
Schema.txt
COL1,5
COL2,2
COL3,4
COL4,3
COL5,6
So the above schema.txt file contains the column list.It also contains the width of each field. Our source will always be a fixed width flat file. Our objective will be to convert it into csv.
Source1.txt
11111223333444555555
11111223333444555555
Target1.txt
11111,22,3333,444,555555
11111,22,3333,444,555555
Source2.txt
11111 333344466666
11111223333 66666
Target2.txt
11111,,3333,444,66666
11111,22,333,,66666
so it should be able to handle space and blanks as well, as we saw in 2nd Source file.
The schema should be a dynamic file where if we provide the structure the bat file will create a csv exactly like the structure from the source.The final target file should have the header taken from the schema file.
Please help.
My present code is given below:
echo off
setlocal EnableDelayedExpansion
echo a,b,c final.txt
rem replace the €€€ string with any unused one
set "fooString=€€€"
for /f "tokens=1 delims=;" %%i in (source.txt) do (
set "x=%%i"
for /f "tokens=1,2 delims=," %%a in (config.txt) do (
call SET "VARraw=!x:~%%a,%%b!%fooString%"
rem replaced with respect to the OP's comment: for %%p in (!VARraw!) do (
for /F "tokens=*" %%p in ("!VARraw!") do (
set "rav=%%p"
set "var=!rav:%fooString%=!"
echo/|set /p "=!var!,"
) final.txt
)
)
Present config.txt contains
0,9
9,3
12,11
23,7
30,1
But i want to modify it.Want to keep only the Field name and the width. Not the starting position and the width.
Problem with existing code is that it prints the result in one single line but i want the \n after the end of each line.
#echo off
setlocal EnableDelayedExpansion
rem Load the schema
set /A numCol=0, maxSpc=0
set "header="
set "spaces="
for /F "tokens=1,2 delims=," %%a in (Schema.txt) do (
set /A numCol+=1
set "header=!header!,%%a"
set "col[!numCol!]=%%b"
if %%b gtr !maxSpc! (
set /A spc=%%b-maxSpc, maxSpc=%%b
for /L %%i in (1,1,!spc!) do set "spaces=!spaces! "
)
)
rem Process the input file
echo %header:~1%
for /F "delims=" %%a in (%1) do (
set "in=%%a"
set "start=0"
set "out="
for /L %%i in (1,1,%numCol%) do for /F "tokens=1,2" %%j in ("!start! !col[%%i]!") do (
set "col=!in:~%%j,%%k!"
if "!col!" equ "!spaces:~0,%%k!" set "col="
set "out=!out!,!col!"
set /A start+=%%k
)
echo !out:~1!
)
Output of example session:
C:\> type Schema.txt
COL1,5
COL2,2
COL3,4
COL4,3
COL5,6
C:\> type Source1.txt
11111223333444555555
11111223333444555555
C:\> test Source1.txt
COL1,COL2,COL3,COL4,COL5
11111,22,3333,444,555555
11111,22,3333,444,555555
C:\> type Source2.txt
11111 333344466666
11111223333 66666
C:\> test Source2.txt
COL1,COL2,COL3,COL4,COL5
11111,,3333,444,66666
11111,22,3333,,66666
The following script (let us call it convert.bat) converts a text file given via command line argument into a CSV file according to your requirements. You may provide the result file as a second argument; if omitted, the output is displayed at the console. The default schema file Schema.txt can be changed if a third argument is specified: (so use like: convert.bat source.txt [target.txt [schema.txt]])
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem Remove leading blanks of every field if this value is non-empty:
set "DELBLANKS=REMOVE"
rem Specify source file as first command line argument:
set "SOURCE=%~1"
rem Specify target file as second argument (optionally):
set "TARGET=%~2"
rem Provide scheme file as third argument (default is "Schema.txt"):
set "SCHEME=%~3"
rem Check the given command line arguments:
if not defined SOURCE >&2 echo ERROR: no source file given! & exit /B 1
if not defined TARGET set "TARGET=con"
if not defined SCHEME set "SCHEME=%~dp0Schema.txt"
rem Read scheme file and build header:
setlocal EnableDelayedExpansion
set "HEADER="
set /A POSITION=0
set /A COLUMN=0
for /F "usebackq tokens=1,2 delims=," %%I in ("!SCHEME!") do (
set /A COLUMN+=1
set "HEADER=!HEADER!,%%I"
if not "%%J"=="" (
set "WIDTH=%%J"
set /A WIDTH[!COLUMN!]+=WIDTH
set /A POSITION[!COLUMN!]=POSITION
set /A POSITION+=WIDTH
)
)
rem Convert source file into CSV format and store to target file:
> "!TARGET!" (
echo(!HEADER:~1!
for /F usebackq^ delims^=^ eol^= %%L in ("!SOURCE!") do (
setlocal DisableDelayedExpansion
set "LINE=%%L"
setlocal EnableDelayedExpansion
set "LINE=!LINE:,=;!"
set "CSV="
for /L %%C in (1,1,%COLUMN%) do (
for /F "tokens=1,2 delims=," %%P in ("!POSITION[%%C]!,!WIDTH[%%C]!") do (
if defined DELBLANKS (
for /F tokens^=*^ eol^= %%S in ("!LINE:~%%P,%%Q!,") do (
for /F "delims=" %%T in (""!CSV!"") do (
endlocal
set "CSV=%%~T%%S"
setlocal EnableDelayedExpansion
set "LINE=!LINE:,=;!"
)
)
) else (
set "CSV=!CSV!!LINE:~%%P,%%Q!,"
)
)
)
if defined CSV echo(!CSV:~,-1!
endlocal
endlocal
)
)
endlocal
endlocal
exit /B
The headers in the schema file should not contain any exclamation marks !.
Any commas , in the source file will be replaced by semicolons ;.
Related
I would like to make a script that given 2 .txt files, it creates N files named as the values inside the first .txt file, and insert in that file the value inside the second .txt file.
[FILE_1].txt
name_1
name_2
name_3
name_4
[FILE_2].txt
text_1
text_2
text_3
text_4
Result:
name_1.html (with inside the string "text_1")
name_2.html (with inside the string "text_2")
name_3.html (with inside the string "text_3")
name_4.html (with inside the string "text_4")
In order to take the values inside the .txt file I use:
setlocal EnableDelayedExpansion
set i=0
for /F %%a in (file_1.txt) do (
set /A i+=1
set array[!i!]=%%a
)
set n=%i%
set s=0
for /F %%a in (file_2.txt) do (
set /A s+=1
set array[!s!]=%%a
)
set v=%s%
endlocal
(I know the number of elements in each file (they are the same))
How would you do it? I tried a lot of variations, with no success, like:
for /F %%a in (file_2.txt) do (
for /l %%v in (1, 1, 92) do (
echo %%~nxa
)>> %%~nxv.html
)
...
set array{!s!}=%%a
...
To create array{*} instead of array[*]
Then
for /L %%v in (1,1,%s%) do >"!array[%%v]!.html" echo !array{%%v}!
Of course, you could also call the arrays something bizarre like names and texts for instance and use the same type of brackets, but I'd be tempted to use name:%%i and text:%%s to avoid the brackets completely. (: because it can't exist within a filename) name_%%i and text_%%s to avoid the brackets completely. (: didn't work properly, changed to _ that worked; Other unlikely-to-start-a-line characters like ] would no doubt also work)
---- [actual test code]
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] 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"
SET "filename1=%sourcedir%\q65556186.txt"
SET "filename2=%sourcedir%\q65556186_2.txt"
set i=0
for /F "usebackq" %%a in ("%filename1%") do (
set /A i+=1
set array[!i!]=%%a
)
set n=%i%
set s=0
for /F "usebackq" %%a in ("%filename2%") do (
set /A s+=1
set array{!s!}=%%a
)
for /L %%v in (1,1,%s%) do >"%destdir%\!array[%%v]!.html" echo !array{%%v}!
TYPE "%destdir%\*.html"
GOTO :EOF
[results]
u:\your results\name_1.html
text_1
u:\your results\name_2.html
text_2
u:\your results\name_3.html
text_3
u:\your results\name_4.html
text_4
[with changes to code for naming purposes]
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
rem The following settings for the source directory, destination directory, target directory,
rem batch directory, filenames, output filename and temporary filename [if shown] 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"
SET "filename1=%sourcedir%\q65556186.txt"
SET "filename2=%sourcedir%\q65556186_2.txt"
set i=0
for /F "usebackq" %%a in ("%filename1%") do (
set /A i+=1
set names_!i!=%%a
)
set n=%i%
set s=0
for /F "usebackq" %%a in ("%filename2%") do (
set /A s+=1
set texts_!s!=%%a
)
for /L %%v in (1,1,%s%) do >"%destdir%\!names_%%v!.html" echo !texts_%%v!
TYPE "%destdir%\*.html"
GOTO :EOF
[Same results]
You could probably do it like this:
#SetLocal EnableExtensions EnableDelayedExpansion
#(For /F UseBackQ^ Delims^=^ EOL^= %%G In ("[FILE_1].txt") Do 1> "%%G.html" (Set /P "}="&Echo(!}!)) 0< "[FILE_2].txt"
lets say that i have test.txt with this lines
1
2
3
i need batch file to rewrite this file as
3
2
1
in new txt file
i tried this to copy last line
for /f "delims=" %%A in (ttt.txt) do set last=%%A
echo %last%>>ttt_lastline.txt
and this to delete last line
#echo off & setlocal EnableDelayedExpansion
set row=
for /F "delims=" %%j in (File.txt) do (
if defined row echo.!row!>> File.new
set row=%%j
)
but wasn't helpful
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "destdir=U:\destdir"
SET "filename1=100lines.txt"
SET "outfile=%destdir%\outfile.txt"
SET /a count=0
FOR /f "delims=" %%a IN (%filename1%) DO (
SET /a count+=1
SET "line[!count!]=%%a"
)
(
FOR /L %%a IN (%count%,-1,1) DO ECHO(!line[%%a]!
)>"%outfile%"
GOTO :EOF
You would need to change the setting of destdir to suit your circumstances.
I used a file named 100lines.txt containing some dummy data for my testing.
Produces the file defined as %outfile%
Using delayedexpansion, read each line into line[?] using !count!, then simply echo each line loaded in reverse order.
This is a Vbscript solution.
Create a file named reverse.vbs and use this as the code.
Dim Stack: Set Stack = CreateObject("System.Collections.Stack")
Do While Not WScript.StdIn.AtEndofStream
Stack.Push WScript.StdIn.ReadLine
Loop
WScript.StdOut.WriteLine Join(Stack.ToArray, vbCrLf)
Now to reverse your file execute this from a cmd prompt or a batch file.
type input.txt |cscript //nologo Reverse.vbs>>output.txt
#echo off
setlocal enabledelayedexpansion
for /f %%a in (forward.txt) do
(
set reversed=%%a !reversed!
)
for %%i in (!reversed!) do echo.%%i >> reversed.txt
goto :eof
I have some problem writing a code for a batchfile that will replace the first part of a file name.
let say we have the files:
abcd123.txt
abcd345.txt
the numeric part(and the extensions) is the part I want to keep and change it to blabla123.txt and blabla345.txt
the numeric part is not always the same.
I tried to write:
set FILE =%1
set LastPart = %FILE:~-7%
set NewName = c:\MyFolder\blabla%LastPart%
ren %FILE% %NewName%
but it didn't worked because there's space between c:\MyFolder\blabla to 123.txt
Perhaps:
SET "OldName=%~n1"
SET "Ext=%~x1"
SET "LastPart=%OldName:~-3%"
SET "FirstPart=blabla
SET "NewFold=C:\MyFolder"
REN "%~1" "%NewFold%\%FirstPart%%LastPart%%Ext%"
Please see if below script helps you. It iterates through all files in a given directory and renames them according to your requirement.
#echo OFF
setlocal ENABLEDELAYEDEXPANSION
REM Get input directory from user
set /p INPUT_DIR=Please enter full path to directory with files, use double quotes if any space:
cd /d %INPUT_DIR%
for /f %%f in ('dir /b %INPUT_DIR%') do (
set newname=hello!fullname:~-7!
ren %%f !newname!
)
Output
E:>dir /b "E:\Temporary\SO\batch\Input - Space"
adadadadad123.txt
E:>Temporary\SO\batch\test_ren.bat
Please enter full path to directory with files, use double quotes if any
space:"E:\Temporary\SO\batch\Input - Space"
E:>dir /b "E:\Temporary\SO\batch\Input - Space"
hello123.txt
Although the question is not quite clear to me, I decided to provide an answer, because the task of extracting a numeric part from the end of a string appears not to be that trivial, particularly in case both the preceding string and the numeric portions may have different lengths.
So here is a script that accepts file paths/names/patterns provided as command line arguments, splits off ther numeric part, prepends an optional prefix to it and renames the file accordingly (actually it just echoes the ren command line for testing; remove the upper-case ECHO to actually rename):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "PREFIX="
for %%F in (%*) do (
for /F "tokens=1-2 delims=0123456789 eol=0" %%K in ("_%%~nF") do (
if "%%L"=="" (
set "FLOC=%%~F"
set "FILE=%%~nF"
set "FEXT=%%~xF"
set "FNEW="
setlocal EnableDelayedExpansion
set "FILE=_!FILE!"
for /L %%E in (0,1,9) do (
set "NAME=!FILE:*%%E=%%E!"
if not "!NAME!"=="!FILE!" (
if 1!NAME! GTR 1!FNEW! (
set "FNEW=!NAME!"
)
)
)
ECHO ren "!FLOC!" "!PREFIX!!FNEW!!FEXT!"
endlocal
)
)
)
endlocal
exit /B
The script skips all files that have less or more than exactly one numeric part in their names, and also those where the numeric part is followed by something other than the file name extension. For example, abcd1234.txt is processed, whereas abcd.txt, 1234.txt, ab1234cd.txt, 1234abcd.txt and ab12cd34.txt are skipped. Note that the numeric part is limited to nine decimal figures.
If the limit of nine digits is disturbing, the following script can be used. It is very similar to the aforementioned one, but a numeric comparison has been replaced by a string comparison with the numbers padded by leading zeroes to have equal lengths. Therefore the string comparison provides the same result as a pure numeric comparison:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "PREFIX="
set /A "DIGS=256"
setlocal EnableDelayedExpansion
for /L %%E in (1,1,%DIGS%) do set "PADZ=!PADZ!0"
endlocal & set "PADZ=%PADZ%"
for %%F in (%*) do (
for /F "tokens=1-2 delims=0123456789 eol=0" %%K in ("_%%~nF") do (
if "%%L"=="" (
set "FLOC=%%~F"
set "FILE=%%~nF"
set "FEXT=%%~xF"
set "FNEW="
setlocal EnableDelayedExpansion
set "FILE=_!FILE!"
for /L %%E in (0,1,9) do (
set "NAME=!FILE:*%%E=%%E!"
if not "!NAME!"=="!FILE!" (
set "CMPN=%PADZ%!NAME!"
set "CMPF=%PADZ%!FNEW!"
if "!CMPN:~-%DIGS%!" GTR "!CMPF:~-%DIGS%!" (
set "FNEW=!NAME!"
)
)
)
ECHO ren "!FLOC!" "!PREFIX!!FNEW!!FEXT!"
endlocal
)
)
)
endlocal
exit /B
This is a robust and more flexible approach, which allows to specify what numeric part to extract by its (zero-based) index, in the variable INDEX (a negative value counts from the back, so -1 points to the last one, if you prefer that):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "PREFIX=blah" & rem // (optional prefix to be used for the new file names)
set /A "INDEX=0" & rem // (`0` means first numeric part, `-1` means last one)
rem // Loop through command line arguments:
for %%F in (%*) do (
set /A "CNT=-1" & set "KIND="
for /F "delims== eol=" %%E in ('2^> nul set "$PART["') do set "%%E="
rem // Store information about currently iterated file:
set "FLOC=%%~F"
set "FILE=%%~nF"
set "FEXT=%%~xF"
rem // Toggle delayed expansion to avoid troubles with `!`:
setlocal EnableDelayedExpansion
rem // Assemble a list of file name portions of numeric and non-numeric parts:
set "LIST= "!FILE!" "
for /L %%J in (0,1,9) do set "LIST=!LIST:%%J=" %%J "!"
set "LIST=!LIST: "" =!"
rem // Determine file name portions, together with their count and kinds:
for %%I in (!LIST!) do (
endlocal & set /A "CNT+=1"
set "ITEM=%%~I" & set "TEST=%%I"
setlocal EnableDelayedExpansion
if "!TEST!"=="!ITEM!" (set "KND=0") else (set "KND=-")
for /F %%K in ("KIND=!KIND!!KND!") do (
for /F "delims=" %%E in ("$PART[!CNT!]=!ITEM!") do (
endlocal & set "%%K" & set "%%E"
)
)
setlocal EnableDelayedExpansion
)
rem // Retrieve the desired numeric file name portion:
if %INDEX% lss 0 (set /A "INDEX=-(1+INDEX)")
if %INDEX% lss 0 (set "RANGE=!CNT!,-1,0") else (set "RANGE=0,1,!CNT!")
set /A "IDX=-1" & set "FNEW=" & for /L %%J in (!RANGE!) do (
if "!KIND:~%%J,1!"=="0" set /A "IDX+=1" & (
if !IDX! equ !INDEX! for %%I in (!IDX!) do set "FNEW=!$PART[%%J]!"
)
)
rem // Actually rename file:
if defined FNEW (
ECHO ren "!FLOC!" "!PREFIX!!FNEW!!FEXT!"
)
endlocal
)
endlocal
exit /B
I want to make a generic script which will convert a fixed width flat file into csv. Below is my approach:
`echo off
setlocal EnableDelayedExpansion
echo a,b,c>final.txt
for /f "tokens=1 delims=;" %%i in (source.txt) do (
set x=%%i
for /f "tokens=1,2 delims=," %%a in (config.txt) do (
call SET VAR=!x:~%%a,%%b!
for %%p in (!VAR!) do (echo/|set /p ="%%p,"
) >>final.txt
)
)
`
Config file which I am using contains the parameters for substring which states from where to do the substring and how many characters.
Config file contains:
0,9
9,3
12,11
23,7
30,1
31,1
32,5
37,9
46,9
55,3
58,9
67,9
76,9
85,9
94,1
Source file contains the actual fixed with source.
Now with my code I am getting the result but for the fields which has no value/empty in the source is not reflecting in the final output.
Example:
Source:
1234<space>678 [col1=678,col2=space,col3=678]
Output (Current):
1234,678
Output(Expected):
1234,,678
Please help
Your for %%p in (!VAR!) do (…) loop executes defined (…) command for all strings found in !VAR! delimited with white space(s). So if !VAR! results to all white spaces, then consequential for %%p in ( ) do (…) loop executes nothing. Next code snippet could help:
echo off
setlocal EnableDelayedExpansion
echo a,b,c>final.txt
rem replace the €€€ string with any unused one
set "fooString=€€€"
for /f "tokens=1 delims=;" %%i in (source.txt) do (
set "x=%%i"
for /f "tokens=1,2 delims=," %%a in (config.txt) do (
call SET "VARraw=!x:~%%a,%%b!%fooString%"
rem replaced with respect to the OP's comment: for %%p in (!VARraw!) do (
for /F "tokens=*" %%p in ("!VARraw!") do (
set "rav=%%p"
set "var=!rav:%fooString%=!"
echo/|set /p "=!var!,"
) >>final.txt
)
)
Edit: note that for /F "tokens=*" %%p in ("!VARraw!") do ( would remove leading spaces from the !VARraw! string.
I need to run a process on many items and the process takes a configuration file as input. The configuration file needs to be changed for each item at three different lines (1,2,17) with different extensions. I can read the configuration file into batch script as a text file but it should be saved with *.cfg configuration so that it can be used. I have put together the following pseudo code with pointers where I would need help for making it functioning batch script.
set inputline=1
set outputline=2
set xmlline=17
set infile=config.txt
set items=list.txt
for /f "delims=" %%a in (%items%) do (
echo.%%a
set curr=1
for /f "delims=" %%b in (%infile%) do (
if !curr!==%inputline% [replace this line in infile with "a".ext1]
if !curr!==%outputline% [replace this line in infile with "a".ext2]
if !curr!==%xmlline% [replace this line in infile with "a".ext3]
)
set /b "curr = curr + 1"
[save "infile".cfg]
)
"call" proccess.exe -config.cfg
)
And the configuration file:
sample.264
sample.yuv
test_rec.yuv
1
1
0
2
500000
104000
73000
leakybucketparam.cfg
1
2
2
0
1
sample.xml
3
Batch has no built in way of replacing a single line in a text file - however you can read the entire contents of the file, change the lines, then rewrite the file.
set file=config.txt
setLocal enableDelayedExpansion
set count=0
for /F "delims=~!" %%b in ('type %file%') do (
set /a count=!count!+1
set line!count!=%%b
)
set line1="a".ext1
set line2="a".ext2
set line17="a".ext3
del %file%
for /L %%c in (1,1,!count!) do echo !line%%c!>>%file%
pause
I slightly modified what I did here. I took out the check to see if the file exists, as you should be able to assume that it will.
Thanks unclemeat, it helped me to nail-down the following working code for me:
set file=config.cfg
set vdos=test.txt
setlocal enabledelayedexpansion
for /f "delims=" %%a in (%vdos%) do (
echo %%a
set count=0
for /F "delims=~!" %%b in ('type %file%') do (
set /a count=!count!+1
set line!count!=%%b
)
set line1=%%a%.264
set line2=%%a%.yuv
set line17=%%a%.xml
del %file%
for /L %%c in (1,1,!count!) do echo !line%%c!>>%file%
ldecod config.cfg
)