I need to have a batch file to combine two text files. My files are:
file1.txt
1
2
3
4
file2.txt
A
B
C
D
E
F
G
H
I
J
K
L
I need to get mixfile that looks like this
mix.txt
1
A
B
C
D
2
E
F
G
H
3
I
J
K
L
Note: for each line of file 1 I need 4 lines from file 2. 1->1-4,2->5-8, 3->9-12
I tried this program (bat file solution), but donot know, how to modify it to get the results with my requirements.
#echo off
set f1=file1.txt
set f2=file2.txt
set outfile=mix.txt
type nul>%outfile%
(
for /f "delims=" %%a in (%f1%) do (
setlocal enabledelayedexpansion
set /p line=
echo(%%a!line!>>%outfile%
endlocal
)
)<%f2%
pause
You will need some kind of line counter:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Improved quoted `set` syntax:
set "f1=file1.txt"
set "f2=file2.txt"
set "outfile=mix.txt"
set "quotient=4"
rem // Redirect the whole block once:
< "%f1%" > "%outfile%" (
rem // Temporarily precede each line with a line number:
for /f "delims=" %%a in ('findstr /N "^" "%f2%"') do (
rem // Get modulo of the line number:
set "item=%%a" & set /A "num=(item+quotient-1)%%quotient"
setlocal EnableDelayedExpansion
rem // Return a line from the other file only if modulo is zero:
if !num! equ 0 (
set "line=" & set /P line=""
echo(!line!
)
rem // Return current line with the line number prefix removed:
echo(!item:*:=!
endlocal
)
)
endlocal
pause
The length of file2.txt determines how many iterations occur.
Related
This question already has an answer here:
Split a CSV file into multiple files with header and given number of records
(1 answer)
Closed 1 year ago.
I have a text file. The first line is header. rest of the lines are data. It may contain thousand lines of data. I need to write a batch script which will split the master files into many files each of them contains maximum 500 lines of data and the same header as master file.
Master file
heder
1
2
3
4
.
.
.
.
1501
it will split the file into 4 files. The fourth one will have the header and 1501
You can get a total count of lines in a file using find and calculate the number of files needed by using a for /l loop on the count of the lines in steps of 500
the below approach examples such - in this way files are created with the header and lines output in accordance with the 500 per file using a paired GTR LEQ conditional test.
#Echo off & CD /D "%~dp0"
:# Primary environment has Delayed Expansion Disabled until after assignment of input
:# to retain '!' characters.
Setlocal EnableExtensions DisableDelayedExpansion
Set "line[i]="
Set "files="
:# Get a count of total lines and how many files to make per 500
for /f %%a in ('type "infile.txt"^|find "" /v /c') do Set /A TTL=%%a-1
For /l %%i in (0 500 %TTL%)Do Set /A files+=1
Set /P "Header=" <"infile.txt"
:# Delayed expansion provides protection against poison characters
Setlocal EnableDelayedExpansion
:# Create or Overide each outfile using the assigned input from set /p
For /l %%i in (1 1 %files%)Do >"Outfile%%i.txt" Echo(!Header!
Endlocal
:# Outer for /f loop skips header line; counts each line in.
:# Inner for /l loop iterates over group size with assigned offset 'Stop'
:# Dual GTR LEQ conditional test of Lne[i] used to output in desired group
For /f "Skip=1 Delims=" %%G in (infile.txt)Do (
Set /A "Line[i]+=1"
Set "Line=%%G"
Setlocal EnableDelayedExpansion
Set "file[i]=0"
For /l %%i in (0 500 !TTL!)Do (
Set /A "Stop=%%i+500"
Set /A "file[i]+=1"
If !Line[i]! GTR %%i If !Line[i]! LEQ !Stop! (
Title File: !file[i]! / !files! Line: !Line[i]! / !TTL!
>>"Outfile!file[i]!.txt" Echo(!Line!
)
)
Endlocal
)
Here you go:
#echo off
setlocal EnableDelayedExpansion
set /a maxNoOfLinesPerFile = 500
set /a lineCount = 0
set /a fileCount = 0
set header=""
set outFileNamePrefix=outFile
for /F "tokens=*" %%A in (source.txt) do (
if !lineCount!==0 (
set header=%%A
) else (
set /a n = !lineCount! %% !maxNoOfLinesPerFile!
REM echo !n!
if !n!==1 (
set /a fileCount = fileCount + 1
set outFileName=!outFileNamePrefix!_!fileCount!.txt
echo !outFileName!
echo !header! >> !outFileName!
echo %%A >> !outFileName!
) else (
echo %%A >> !outFileName!
)
)
set /a lineCount = lineCount + 1
)
how please can I 'pivot' or transpose a file (i.e. turn a single-column list, into a table of data)...
Currently...
VideoA.name
VideoA.size
VideoA.bitrate
VideoB.name
VideoB.size
VideoB.bitrate
...
Desired...
VideoA.name, VideoA.size, VideoA.bitrate
VideoB.name, VideoB.size, VideoB.bitrate
Name
Size
Bitrate
VideoA.name
VideoA.size
VideoA.bitrate
VideoB.name
VideoB.size
VideoB.bitrate
Extra Info / Context
I'm aware people often ask 'why are you doing this?' so (if interested), here is the wider context / problem I am trying to solve...
I have a list of files in Files.txt
I have a jscript batch file getProps.bat that extract file properties and prints them, 1 per line
I have written a batch file to loop through Files.txt, get the properties of each and write the output to Details.csv
However if I have 500 files x 3 properties, this currently gives me 1500 lines, and I want 500 lines x 3 columns
GetProps_AllFiles.bat
---------------------
#ECHO OFF
SETLOCAL
FOR /F "tokens=*" %%A in (Files.txt) do (
getprops %%A 0,1,320 /noheaders >> Details.csv
)
Thanks in advance!
Use the "standard way" (for /f) to read a file line by line, extended by a counter. Add the line to a string (line), followed by a comma (or whatever you want to use as separator), and increase the counter. Except it's the third line. Then print the string plus the current line, reset the counter and string, and repeat.
#echo off
setlocal enabledelayedexpansion
set "line="
set count=0
(for /f "delims=" %%a in (test.txt) do (
set /a count+=1
if !count! equ 3 (
echo !line!%%a
set "line="
set count=0
) else (
set line=!line!%%a,
)
))>test.csv
The below is a slight adjustment to the code kindly provided by Stephan that allows a filename and number of lines to be passed into the script...
ColumiseFile.cmd
----------------
#ECHO OFF
SETLOCAL enabledelayedexpansion
REM :: USAGE -----------------------------------------------------------------
REM ColumiseFile [1]File.txt [2]NumOfLines
REM > Concatenates every n Lines into 1, exporting result to File.csv
SET "File=%1"
SET /A Lines=%2
REM :: MAIN -------------------------------------------------------------------
REM Thanks to Stephan [https://stackoverflow.com/a/67664755/15919675]
REM Loops through input file, compacting every n lines into 1
set "line="
set count=0
(for /f "delims=" %%a in (%File%) do (
set /a count+=1
if !count! equ %Lines% (
echo !line!%%a
set "line="
set count=0
) else (
set line=!line!%%a,
)
REM :: OUTPUT -----------------------------------------------------------------
REM Create .csv in same location as source .txt file
))>%~dpn1.csv
So what I'm trying to do is create a find for multiple people where it in the text file it will say names and numbers like
Example of text file:
Beth
1234567891
Jay
2134456544
This is the best way I can explain what I'm trying to do:
#echo off
set "file=Test1.txt"
setlocal EnableDelayedExpansion
<"!file!" (
for /f %%i in ('type "!file!" ^| find /c /v ""') do set /a n=%%i && for /l %%j in (1 1 %%i) do (
set /p "line_%%j="
)
)
set /a Name=1
set /a Number=2
Echo Line_%Name%> %Name%.txt (Im trying to get this to say line_2 to say 1st line in the text file)
Echo Line_%Number%> %Name%.txt (Im trying to get this to say line_2 to say 2nd line in the text file)
:Start
set /a Name=%Name%+2 (These are meant to take off after 1 so lines 3,5,7,9 so on)
set /a Number=%Number%+2 (These are meant to take off after 2 so lines 4,6,8,10 so on)
Echo Line_%Name%
Echo Line_%Number%
GOTO :Start
so the outcome would be
In Beth.txt:
Beth
1234567891
So every name will be a file name and the first line in a file. I will change it later so I can do a addition in each text file.
Name: Beth
Number: 1234567891
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
SET "filename1=%sourcedir%\q65417881.txt"
rem make sure arrays are empty
For %%b IN (name number) DO FOR /F "delims==" %%a In ('set %%b[ 2^>Nul') DO SET "%%a="
rem Initialise counter and entry array
SET /a count=0
SET "number[0]=dummy"
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO (
IF DEFINED number[!count!] (SET /a count+=1&SET "name[!count!]=%%a") ELSE (SET "number[!count!]=%%a")
)
rem clear out dummy entry
SET "number[0]=dummy"
FOR /L %%c IN (1,1,%count%) DO (
rem replace spaces with dashes
SET "name[%%c]=!name[%%c]: =-!"
rem report to console rem report to console
ECHO Name: !name[%%c]! Number: !number[%%c]!
rem generate name.txt file
(
ECHO !name[%%c]!
ECHO !number[%%c]!
)>"%destdir%\!name[%%c]!.txt"
)
GOTO :EOF
You would need to change the values assigned to sourcedir and destdir to suit your circumstances. The listing uses a setting that suits my system.
I deliberately include spaces in names to ensure that the spaces are processed correctly.
I used a file named q65417881.txt containing your data for my testing.
The line data read from the file is assigned to %%a is assigned to and number[!count!] alternately. The data is retained in these arrays for use by further processing.
[Edited to include conversion of spaces within names to dashes]
If I understand correctly, you want to precede every second line with Number: + SPACE and every other line with Name: + SPACE. For this you do not need to store each line in a variable first, you can use a single for /F loop lo read the file line by line and process every line individually. There are two possibilities:
Temporarily precede every line with a line number plus : using findstr /N:
#echo off
rem // Loop through lines and precede each with line number plus `:`:
for /F "tokens=1* delims=:" %%K in ('findstr /N "^" "Test1.txt"') do (
rem // Calculate remainder of division by two:
set /A "MOD=%%K%%2" 2> nul
rem // Toggle delayed expansion to avoid issues with `!`:
setlocal EnableDelayedExpansion
rem // Conditionally return line string with adequate prefix:
if !MOD! neq 0 (
endlocal & echo Name: %%L
) else (
endlocal & echo Number: %%L
)
)
This will fail when a line begins with the a :.
Check whether numeric representation of current line string is greater than 0:
#echo off
rem // Loop through (non-empty) lines:
for /F "usebackq delims=" %%L in ("Test1.txt") do (
rem // Determine numeric representation of current line string:
set /A "NUM=%%L" 2> nul
rem // Toggle delayed expansion to avoid issues with `!`:
setlocal EnableDelayedExpansion
rem // Conditionally return line string with adequate prefix:
if !NUM! equ 0 (
endlocal & echo Name: %%L
) else (
endlocal & echo Number: %%L
)
)
This fails when a name begins with numerals and/or when a numeric line is 0.
And just for the sake of posting something different:
#SetLocal EnableExtensions DisableDelayedExpansion & (Set LF=^
% 0x0A %
) & For /F %%G In ('Copy /Z "%~f0" NUL') Do #Set "CR=%%G"
#For /F "Tokens=1,2* Delims=:" %%G In ('%__AppDir__%cmd.exe /D/V/C ^
"%__AppDir__%findstr.exe /NR "^[a-Z]*!CR!!LF![0123456789]" "Test1?.txt" 2>NUL"
') Do #(SetLocal EnableDelayedExpansion
(Set /P "=Name: %%I!CR!!LF!Number: " 0<NUL & Set "_="
For /F Delims^=^ EOL^= %%J In ('%__AppDir__%more.com +%%H "%%G"') Do #(
If Not Defined _ Set "_=_" & Echo %%J)) 1>"%%I.txt" & EndLocal)
This file should be run with the Test1.txt file in the current working directory. It is important that along side Test1.txt, there are no other .txt files with the same basename followed by one other character, (for example Test1a.txt or Test12.txt). Should you wish to change your filename, just remember that you must suffix its basename in the above code with a ? character, (e.g. MyTextFile.log ⇒ MyTextFile?.log).
I had the rare opportunity to verify that this script worked against the following example Test1.txt file:
Beth
1234567891
Jay
2134456544
Bob
2137856514
Jimmy
4574459540
Mary
3734756547
Gemma
6938456114
Albert
0134056504
I have a huge CSV file that I need to split into small CSV files, keep headers in each file and make sure that all records are kept. For example, here is the original file:
ID Date
1 01/01/2010
1 02/01/2010
2 01/01/2010
2 05/01/2010
2 06/01/2010
3 06/01/2010
3 07/01/2010
4 08/01/2010
4 09/01/2010
If I split the file right, I should see the first 5 records in data_1.csv and the last 4 records in data_2.csv.
The code I have only splits by rows and does not keep the header. I don't know how to modify it:
#echo off
setLocal EnableDelayedExpansion
set limit=5
set file=data.csv
set lineCounter=1
set filenameCounter=1
set name=
set extension=
for %%a in (%file%) do (
set "name=%%~na"
set "extension=%%~xa"
)
for /f "tokens=*" %%a in (%file%) do (
set splitFile=!name!-part!filenameCounter!!extension!
if !lineCounter! gtr !limit! (
set /a filenameCounter=!filenameCounter! + 1
set lineCounter=1
echo Created !splitFile!.
)
echo %%a>> !splitFile!
set /a lineCounter=!lineCounter! + 1
)
Here is a method similar to yours using a for /F loop to read the input file. The performance is not quite good however, because each output file is opened and closed for every single line written:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILE=%~1" & rem // (first command line argument is input file)
set /A "_LIMIT=5" & rem // (number of records or rows per output file)
rem // Split file name:
set "NAME=%~dpn1" & rem // (path and file name)
set "EXT=%~x1" & rem // (file name extension)
rem // Split file into multiple ones:
set "HEADER=" & set /A "INDEX=0, COUNT=0"
rem // Read file once:
for /F "usebackq delims=" %%L in ("%_FILE%") do (
rem // Read header if not done yet:
if not defined HEADER (
set "HEADER=%%L"
) else (
set "LINE=%%L"
rem // Compute line index, previous and current file count:
set /A "PREV=COUNT, COUNT=INDEX/_LIMIT+1, INDEX+=1"
rem // Write header once per output file:
setlocal EnableDelayedExpansion
if !PREV! lss !COUNT! (
> "!NAME!_!COUNT!!EXT!" echo/!HEADER!
)
rem // Write line:
>> "!NAME!_!COUNT!!EXT!" echo/!LINE!
endlocal
)
)
endlocal
exit /B
To accomplish your task you do not even need a for /F loop; rather you could use set /P, together with input redirection, in a for /L loop, like this (see all the explanatory comments):
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILE=%~1" & rem // (first command line argument is input file)
set /A "_LIMIT=5" & rem // (number of records or rows per output file)
rem // Split file name:
set "NAME=%~dpn1" & rem // (path and file name)
set "EXT=%~x1" & rem // (file name extension)
rem // Determine number of lines excluding header:
for /F %%I in ('^< "%_FILE%" find /V /C ""') do set /A "COUNT=%%I-1"
rem // Split file into multiple ones:
setlocal EnableDelayedExpansion
rem // Read file once:
< "!_FILE!" (
rem // Read header (first line):
set /P HEADER=""
rem // Calculate number of output files:
set /A "DIV=(COUNT-1)/_LIMIT+1"
rem // Iterate over output files:
for /L %%J in (1,1,!DIV!) do (
rem // Write an output file:
> "!NAME!_%%J!EXT!" (
rem // Write header:
echo/!HEADER!
rem // Write as many lines as specified:
for /L %%I in (1,1,%_LIMIT%) do (
set "LINE=" & set /P LINE=""
if defined LINE echo/!LINE!
)
)
)
)
endlocal
endlocal
exit /B
The advantage of this method is that the input file as well as each output file is opened once only.
I have a list of letters in a file called "letters.txt" and a list of number of occurrence of each letter in a file called "LetterPerSample.txt",both files are arranged, so first row of letters.txt has "a" second has "b"...etc, and same for SamplePerLetter.txt the first row has max nymber of "a",second has max number of "b" and so in,i want to create a list of files like this a_1,a_2,.....a_max.txt, where max is a number as listed above, and each file generated has it's own letter written inside. So a_1.txt has "a" written inside, b_5.txt has "b" written and so on
what i have done so far is:
#echo off
setlocal enableDelayedExpansion
for /f "tokens=*" %%a in (letters.txt) do (
set letter=%%a
for /f "tokens=*" %%b in (SamplePerLetter.txt) do (
set num=%%b
for/L %%g IN (1,1,!num!) do (
set index=%%g
echo !letter!>letter_labels/!letter!/!letter!!index!.lab
)
)
)
sample of the output
a_1.txt
a_2.txt
...
a_10.txt
b_1.txt
b_2.txt
...
b_10.txt
but a and b doesnt have the same number of occurrence in the file LetterPerSample.txt a has 10 and b has 5, so what's wrong with my code?
This method does not require that the letters in letters.txt file be in order, so you may insert just the desired letters in such file:
#echo off
setlocal EnableDelayedExpansion
rem Load the number of occurrences of each letter from "LetterPerSample.txt" file
set "letters=abcdefghijklmnopqrstuvwxyz"
set "i=0"
for /F %%b in (LetterPerSample.txt) do (
for %%i in (!i!) do set "number[!letters:~%%i,1!]=%%b"
set /A i+=1
)
rem Process the letters in "letters.txt" file (in any order)
for /F %%a in (letters.txt) do (
set "letter=%%a"
set "num=!number[%%a]!"
for /L %%g in (1,1,!num!) do (
set "index=%%g"
echo !letter!>letter_labels\!letter!\!letter!_!index!.lab
)
)
You may review the management of arrays in Batch files at this post.
If letters.txt file have always all the letters, from a to z, then this file contain redundant information that can be eliminated:
#echo off
setlocal EnableDelayedExpansion
rem Load the number of occurrences of each letter from "LetterPerSample.txt" file
rem and create the desired files
set "letters=abcdefghijklmnopqrstuvwxyz"
set "i=0"
for /F %%b in (LetterPerSample.txt) do (
for %%i in (!i!) do set "letter=!letters:~%%i,1!"
set /A i+=1
set "num=%%b"
for /L %%g in (1,1,!num!) do (
set "index=%%g"
echo !letter!>letter_labels\!letter!\!letter!_!index!.lab
)
)
your problem is, to read two files simultanioulsly. Here is a trick to do so:
#echo off
setlocal enabledelayedexpansion
<letterpersample.txt (
for /f %%a in (letters.txt) do (
set /p num=
for /l %%i in (1,1,!num!) do (
echo %%a>letter_labels\%%a\%%a%%i.lab
)
)
)
The for loop (%%a) reads one line after the other from letters.txt. set /p reads a line from STDIN (which is redirected from letterspersample.txt), so if for reads line number 5 from one file, set /p reads line number 5 from the other.
(PS: I doubt, your echo logic is ok. Seems odd)