Reputation: 19
OS: Windows 7
I need to output two lines; one from each text file, side by side. Similar to what has been shown here.
A.txt;
1
2
3
4
5
B.txt;
A
B
C
D
E
So I would like to echo;
1 A
2 B
3 C
4 D
5 E
Upvotes: 0
Views: 3466
Reputation: 49086
The Windows Command Processor cmd.exe
processing a batch file is the worst choice for such a text files merging task as it is designed for executing commands and executables and not for processing text files.
But this text lines merging task can be done with a batch file if the files two merge are not too large and the lines are not too long which means the line output by command ECHO must have less than 8192 characters not counting the newline characters carriage return and line-feed.
@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FileA=%~dp0A.txt"
set "FileB=%~dp0B.txt"
set "ResultsFile=%~dp0Merged AB.txt"
if not exist "%FileA%" echo ERROR: Missing file: "%FileA%"& exit /B
if not exist "%FileB%" echo ERROR: Missing file: "%FileB%"& exit /B
set "FileALinesCount=0"
set "FileBLinesCount=0"
for /F "delims==" %%I in ('set Line 2^>nul') do set "%%I="
for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /R /N "^" "%FileA%"') do for /F delims^=:^ eol^= %%J in ("%%I") do set "LineA%%J=%%I" & set "FileALinesCount=%%J"
for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /R /N "^" "%FileB%"') do for /F delims^=:^ eol^= %%J in ("%%I") do set "LineB%%J=%%I" & set "FileBLinesCount=%%J"
if %FileALinesCount% GEQ %FileBLinesCount% (set "LinesCount=%FileALinesCount%") else set "LinesCount=%FileBLinesCount%"
if %LinesCount% == 0 del "%ResultsFile%" 2>nul & exit /B
setlocal EnableDelayedExpansion
(for /L %%I in (1,1,%LinesCount%) do (
if defined LineA%%I (
if defined LineB%%I (
echo(!LineA%%I:*:=! !LineB%%I:*:=!
) else echo(!LineA%%I:*:=!
) else echo(!LineB%%I:*:=!
))>"%ResultsFile%"
endlocal
endlocal
This batch file first defines the required execution environment by disabling command echo mode, enabling command extensions and disabling delayed environment variable expansion.
Next is checked if the files A.txt
and B.txt
exist both in the directory of the batch file otherwise an error message is output and the batch file processing ends.
The first FOR loop deletes all environment variables which are by chance already defined with a name starting with Line
.
The second FOR loop runs one more command process in background with %ComSpec% /c
and the FINDSTR command line appended as additional arguments which just outputs all lines with line number and colon of file A.txt
. The output lines are captured by FOR and assigned completely to loop variable I
. For each line one more FOR is used to get the line number left to the colon and define next an environment variable with name LineA
and the line number appended with the entire line output by FINDSTR assigned as value. The current line number is additionally assigned to the environment variable FileALinesCount
.
The third FOR loop does the same for all lines in file B.txt
.
The number of lines of each file could be different. For that reason the IF condition finds out what is the greatest lines count value and assigns it to the environment variable LinesCount
.
The results file is deleted on already existing (from a previous execution of the batch file) on file A.txt
and B.txt
both exist, but are both empty files.
Next one more FOR loop is used now in an environment with enabled delayed environment variable expansion to output the lines from the two files merged together on one line with using a space character between them. In case of file A.txt
has more lines than file B.txt
, then just the line of file A.txt
is output if there is no more line from file B.txt
. In case of file B.txt
has more lines than file A.txt
, then just the line of file B.txt
is output if there is no more line from file A.txt
. The output lines are written into the results files as defined at top of the batch file. The line number and the colon added by FINDSTR on output of all lines to standard output stream of background command process are removed during the output of the lines by using a string substitution.
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
call /?
... explains %~dp0
... drive and path of argument 0 which is the batch file pathdel /?
echo /?
endlocal /?
exit /?
findstr /?
for /?
if /?
set /?
setlocal /?
See also: How to read and print contents of text file line by line?
Some additional information about the line length limitations can be read on the Microsoft documentation pages:
The argument string of command SET or command ECHO cannot have more than 8191 characters.
In the batch file code above the argument string of command SET is everything after set
and the space character separating the command from its argument, i.e. the quotation mark "
, the variable name, the equal sign =
, the string value and once again the quotation mark "
.
The argument string of command ECHO is in the batch file everything after the command echo
and left parenthesis (
used as separator instead of a space character to output correct also an empty line or a line starting with /?
.
Here is an example to demonstrate the command line argument(s) string length limitation of 8191 characters.
There is a batch file LengthTest.cmd
with the following command lines:
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set "InputFile=%~dp0Length Test Input.txt"
if not exist "%InputFile%" exit /B
set "OutputFile=%~dp0Length Test Output"
del "%OutputFile% *.txt" 2>nul
(for /F "usebackq delims=" %%I in ("%InputFile%") do (
echo(%%I
set "Line=%%I"
echo(!Line!
))>"%OutputFile% 1_1.txt"
(for /F "usebackq delims=" %%I in ("%InputFile%") do (
echo(%%I
set Line=%%I
echo(!Line!
))>"%OutputFile% 2_1.txt"
(for /F "usebackq delims=" %%I in ("%InputFile%") do (
echo(%%I
set L=%%I
echo(!L!
))>"%OutputFile% 3_1.txt"
(for /F "usebackq delims=" %%I in ("%InputFile%") do (
echo(%%I
set L=%%I
echo(!L! !L!
))>"%OutputFile% 4_1.txt"
(for /F "usebackq delims=" %%I in ("%InputFile%") do (
echo(%%I
))>"%OutputFile% 5_1.txt"
for /F "usebackq delims=" %%I in ("%InputFile%") do (
echo(%%I>>"%OutputFile% 1_2.txt"
set "Line=%%I"
echo(!Line!>>"%OutputFile% 1_2.txt"
)
for /F "usebackq delims=" %%I in ("%InputFile%") do (
echo(%%I>>"%OutputFile% 2_2.txt"
set Line=%%I
echo(!Line!>>"%OutputFile% 2_2.txt"
)
for /F "usebackq delims=" %%I in ("%InputFile%") do (
echo(%%I>>"%OutputFile% 3_2.txt"
set L=%%I
echo(!L!>>"%OutputFile% 3_2.txt"
)
for /F "usebackq delims=" %%I in ("%InputFile%") do (
echo(%%I>>"%OutputFile% 4_2.txt"
set L=%%I
echo(!L! !L!>>"%OutputFile% 4_2.txt"
)
for /F "usebackq delims=" %%I in ("%InputFile%") do (
echo(%%I>>"%OutputFile% 5_2.txt"
)
endlocal
In the directory of this batch file is the text file Length Test Input.txt
which has six lines ending all with carriage return and line-feed. The six lines are:
Line 1 - 8184 chars: 0123456789...0123456789abc
Line 2 - 8186 chars: 0123456789...0123456789abcde
Line 3 - 8189 chars: 0123456789...0123456789abcdefgh
Line 4 - 8190 chars: 0123456789...0123456789abcdefghi
Line 5 - 8191 chars: 0123456789...0123456789abcdefghij
Line 6 - 8192 chars: 0123456789...0123456789abcdefghijk
...
is used here as a placeholder for 814 repetitions of 0123456789
.
The execution of this batch file produces ten files.
Length Test Output 1_1.txt
and Length Test Output 1_2.txt
contain:
Line 1 - 8184 chars: 0123456789...0123456789abc
Line 1 - 8184 chars: 0123456789...0123456789abc
Length Test Output 2_1.txt
and Length Test Output 2_2.txt
contain:
Line 1 - 8184 chars: 0123456789...0123456789abc
Line 1 - 8184 chars: 0123456789...0123456789abc
Line 2 - 8186 chars: 0123456789...0123456789abcde
Line 2 - 8186 chars: 0123456789...0123456789abcde
Length Test Output 3_1.txt
and Length Test Output 3_2.txt
contain:
Line 1 - 8184 chars: 0123456789...0123456789abc
Line 1 - 8184 chars: 0123456789...0123456789abc
Line 2 - 8186 chars: 0123456789...0123456789abcde
Line 2 - 8186 chars: 0123456789...0123456789abcde
Line 3 - 8189 chars: 0123456789...0123456789abcdefgh
Line 3 - 8189 chars: 0123456789...0123456789abcdefgh
Length Test Output 4_1.txt
and Length Test Output 4_2.txt
contain:
Line 1 - 8184 chars: 0123456789...0123456789abc
Line 2 - 8186 chars: 0123456789...0123456789abcde
Line 3 - 8189 chars: 0123456789...0123456789abcdefgh
Length Test Output 5_1.txt
and Length Test Output 5_2.txt
contain:
Line 1 - 8184 chars: 0123456789...0123456789abc
Line 2 - 8186 chars: 0123456789...0123456789abcde
Line 3 - 8189 chars: 0123456789...0123456789abcdefgh
Line 4 - 8190 chars: 0123456789...0123456789abcdefghi
Line 5 - 8191 chars: 0123456789...0123456789abcdefghij
Conclusion:
cmd.exe
and then written into a file (*_1.txt
files) or each output is directly written into a file (*_2.txt
files) on processing small file(s).echo(!L! !L!
. The two created output files Length Test Output 4_1.txt
and Length Test Output 4_2.txt
contain only the lines output with echo(%%I
in the two loops.The batch file LengthTest.cmd
produces the same ten files on Windows XP SP3, Windows 7 SP1 and Windows 10 1909.
Upvotes: 1
Reputation: 3756
Code for GNU sed:
sed "s#.*#s/.*/& \&/g;n#" A.txt|sed -f - B.txt
>sed "s#.*#s/.*/& \&/g;n#" A.txt|sed -f - B.txt 1 A 2 B 3 C 4 D 5 E
Upvotes: 0
Reputation: 6630
Try this:
@echo off
setlocal enabledelayedexpansion
set /a count=0
For /f %%a in (A.txt) do (
set /a count=!count!+1
set A!count!=%%a
)
set count=0
For /f %%b in (B.txt) do (
set /a count=!count!+1
set B!count!=%%b
)
set recount=0
:loop
recount=%recount%+1
echo %A!recount!% %B!recount!%
if %recount% gtr %count% goto :end
goto :recount
:end
pause
exit
Hope this helped,
Yours Mona
Note : If there are more lines in A.txt
then it will ignore them. If there are less, then it will show [blank] [line from B.txt]
Upvotes: 0
Reputation: 41224
I had this squirrled away which gives you a technique to solve that.
@echo off
del file1.txt 2>nul
del file2.txt 2>nul
for %%a in (A B C D) do echo %%a>>file2.txt
for %%a in (1 2 3 4) do echo %%a>>file1.txt
@echo off
setlocal DisableDelayedExpansion
< file2.txt (
for /F "delims=" %%a in (file1.txt) do (
set file2Line=
set /P file2Line=
set "file1Line=%%a"
setlocal EnableDelayedExpansion
echo(!file1Line! !file2Line!
endlocal
)
)
pause
del file1.txt 2>nul
del file2.txt 2>nul
goto :EOF
Upvotes: 2