批处理:按列合并 txt 文件

发布于 2024-12-05 18:31:07 字数 2900 浏览 0 评论 0原文

我正在尝试将 txt 文件(其中第一列全部相等)合并到一个文件中。我在实验中获得了数千个。我使用 3 个输入文件作为示例来说明我想要实现的目标:

1.txt     2.txt     3.txt
l1 a1     l1 b1     l1 c1
l2 a2     l2 b2     l2 c2
l3 a3     l3 b3     l3 c3

因此所有输入文件都有共同的第一列。 我的愿望是获得以下输出:

out.txt
l1 a1 b1 c1
l2 a2 b2 c2
l3 a3 b3 c3

Attempt 1 of 3

:: hmm.bat=============================================
@echo off > hmm.txt & setLocal enableDELAYedeXpansion
echo AAAAAAAAAAaaaaaaaaaa............
pushd %*

for /f "tokens=1* delims= " %%a in (a1.txt) do (
>> hmm.txt echo. %%a hm
)

for %%j in (*.txt) do (
   echo. %%j yes? >> hmm.txt
   for /f "tokens=2* delims= " %%a in (%%j) do (
   >> hmm.txt echo. %%a
   )
)
popd
:: End_Of_Batch======================================

此批处理文件确实提取了我想要的列,但不是所有内容都在单独的列中,而是所有数据都在一个列中。我无法设法将输出放入单独的列中。

这次尝试(3 次中的 2 次)最终将给出我想要的:

::=============================================
@echo off > tral.txt & setLocal enableDELAYedeXpansion

set N=
for /f "tokens=1* delims= " %%a in (a1.txt) do (
set /a N+=1 & call :sub1 %%a & set A!N!=!C!
)

set N=
for /f "tokens=* delims= " %%a in (a1.txt) do (
set /a N+=1 & call :sub1 %%a & set B!N!=!C!
)

set N=
for /f "tokens=* delims= " %%a in (a2.txt) do (
set /a N+=1 & call :sub1 %%a & set C!N!=!C!
)

set N=
for /f "tokens=* delims= " %%a in (a3.txt) do (
set /a N+=1 & call :sub1 %%a & set D!N!=!C!
)

for /L %%a in (1 1 !N!) do (
>> tral.txt echo. !A%%a! !B%%a! !C%%a! !D%%a!
)
goto :eof

:sub1 set C to last token
:loop
if '%2' neq '' (
shift
goto :loop
)
set C=%1
goto :eof
::================================================

但是,要将其扩展到许多(数千个)文件,我需要重复该位

set N=
for /f "tokens=* delims= " %%a in (a*.txt) do (
set /a N+=1 & call :sub1 %%a & set x!N!=!C!
)

maaaaaaaany 次。我尝试使用循环来代替:

尝试 3 of 3

::=============================================
@echo off & setLocal enableDELAYedeXpansion
type nul > slow.txt

set N=
for /f "tokens=1* delims= " %%a in (a1.txt) do (
set /a N+=1 & call :sub1 %%a & set A!N!=!C!
)

for %%j in (*.txt) do (
set N=
for /f "tokens=* delims= " %%a in (%%j) do (
set /a N+=1 & call :sub1 %%a & set x!N!=!C!
)
)

for /L %%a in (1 1 !N!) do (
>> slow.txt echo. !A%%a! !x%%a!
)
goto :eof

:sub1 set C to last token
:loop
if '%2' neq '' (
shift
goto :loop
)
set C=%1
goto :eof
::=============================================

我最终得到第一列(所有数据文件都共有)和最后一个数据文件的第二列。 我不知道如何更新 !x%%a! 中的变量 x对于每个文件,将其打印在单独的列中。

或者,有谁知道是否可以在输出文件中所选行的末尾回显数据? 然后,我会将其回显到第一行的末尾,这将导致回显列中的所有数据。 使用

set /P line1=< hmm.txt

and then

echo.%line1% %%a>>hmm.txt

不会导致在第一行末尾出现回显,而是在最后一行末尾出现回显。

任何人都有解决方案吗?

I am trying to merge txt files (from which first column is equal in all) into one file. Thousands of them that I acquire in my experiments. I use 3 input files as an example to illustrate what I am trying to achieve:

1.txt     2.txt     3.txt
l1 a1     l1 b1     l1 c1
l2 a2     l2 b2     l2 c2
l3 a3     l3 b3     l3 c3

So all input files have the first column in common.
My wish is to get this output:

out.txt
l1 a1 b1 c1
l2 a2 b2 c2
l3 a3 b3 c3

Attempt 1 of 3

:: hmm.bat=============================================
@echo off > hmm.txt & setLocal enableDELAYedeXpansion
echo AAAAAAAAAAaaaaaaaaaa............
pushd %*

for /f "tokens=1* delims= " %%a in (a1.txt) do (
>> hmm.txt echo. %%a hm
)

for %%j in (*.txt) do (
   echo. %%j yes? >> hmm.txt
   for /f "tokens=2* delims= " %%a in (%%j) do (
   >> hmm.txt echo. %%a
   )
)
popd
:: End_Of_Batch======================================

This batch file does extract the columns I want, but rather than that everything is in separate columns, all data is in one single column. I have not been able to manage to get output into separate columns.

This attempt (2 of 3) would ultimately give what I want:

::=============================================
@echo off > tral.txt & setLocal enableDELAYedeXpansion

set N=
for /f "tokens=1* delims= " %%a in (a1.txt) do (
set /a N+=1 & call :sub1 %%a & set A!N!=!C!
)

set N=
for /f "tokens=* delims= " %%a in (a1.txt) do (
set /a N+=1 & call :sub1 %%a & set B!N!=!C!
)

set N=
for /f "tokens=* delims= " %%a in (a2.txt) do (
set /a N+=1 & call :sub1 %%a & set C!N!=!C!
)

set N=
for /f "tokens=* delims= " %%a in (a3.txt) do (
set /a N+=1 & call :sub1 %%a & set D!N!=!C!
)

for /L %%a in (1 1 !N!) do (
>> tral.txt echo. !A%%a! !B%%a! !C%%a! !D%%a!
)
goto :eof

:sub1 set C to last token
:loop
if '%2' neq '' (
shift
goto :loop
)
set C=%1
goto :eof
::================================================

However, to extend this to many (thousands) files, I would need to repeat the bit

set N=
for /f "tokens=* delims= " %%a in (a*.txt) do (
set /a N+=1 & call :sub1 %%a & set x!N!=!C!
)

maaaaaaaany times. I have tried using a loop instead:

Attempt 3 of 3

::=============================================
@echo off & setLocal enableDELAYedeXpansion
type nul > slow.txt

set N=
for /f "tokens=1* delims= " %%a in (a1.txt) do (
set /a N+=1 & call :sub1 %%a & set A!N!=!C!
)

for %%j in (*.txt) do (
set N=
for /f "tokens=* delims= " %%a in (%%j) do (
set /a N+=1 & call :sub1 %%a & set x!N!=!C!
)
)

for /L %%a in (1 1 !N!) do (
>> slow.txt echo. !A%%a! !x%%a!
)
goto :eof

:sub1 set C to last token
:loop
if '%2' neq '' (
shift
goto :loop
)
set C=%1
goto :eof
::=============================================

I end up with the first column (which all data files have in common), and the second column of the very last data file.
I do not know how to update the variable x in !x%%a! for each file, to get this printed in a separate column.

Alternatively, does anyone know if it is possible to echo data at the end of a chosen line in the output file?
I would then echo it to the end of the first line, which then would result in echoing all data in columns.
Using

set /P line1=< hmm.txt

and then

echo.%line1% %%a>>hmm.txt

does not result in echoing at the end of the first line, but rather at the end of the last line.

Anyone has a solution either way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

傻比既视感 2024-12-12 18:31:07

与此同时,我设法找到了解决方案(在 http://www.computing.net/answers/programming/merge-files-in-column-output/26553.html)。

也许有一天其他人也能很好地利用它。

首先它计算文件数(稍后使用文件数)。
不带扩展名的文件名列在文件“list.dat”中。

@echo off 
SetLocal EnableDelayedExpansion
for /f  %%a in ('dir/b *.txt') do (
    set /a count+=1
    set /a count1=count-1
)
echo total is !count!
echo !count1!

rem empty contents of files
type nul > x.txt
type nul > y.txt
type nul > z.txt
type nul > list.dat

setlocal
set first=y
(
    for /f %%g in ('dir/b/a-d a*.txt') do (
        if defined first (
            set first=
            set/p=%%~ng <nul
        ) else (
            set/p=%%~ng <nul
        )
    )
)>>list.dat

for /f %%j in (list.dat) do (
    echo. %%j   
    for %%a in (%%j) do find /n /v "" < %%a.txt >> x.txt
)
sort x.txt /o x.txt

set "regex=^\[[0-9]\]"
:loop
findstr /r "%regex%" x.txt >> y.txt
if not errorlevel 1 (
    set "regex=^\[[0-9]%regex:~3%
    goto loop
)

set cnt=
set line=
for /f "delims=" %%a in (y.txt) do (
    set input=%%a
    set input=!input:*]=!
    set line=!line! !input!
    if "!cnt!"=="!count1!" (
        >> z.txt echo !line:~1!
        set line=
    )
    set /a cnt=^(cnt + 1^) %% !count!
)

type nul > zz.dat
for /F "delims=" %%i in (z.txt) do (
    set cnt=1
    set rrow=
    for %%j in (%%i) do (
        set /A cnt-=1
        if !cnt! equ 0 (set cnt=0 & set rrow=!rrow! %%j)
    )
    set cnt=2
    set row=
    for %%j in (%%i) do (
        set /A cnt-=1
        if !cnt! equ 0 (set cnt=2 & set row=!row! %%j)
    )
    set row=!row:~1!
    echo. !rrow! !row!>> zz.dat
)

del x.txt
del y.txt
pause

In the meantime I have managed to find the solution (with much help from others on http://www.computing.net/answers/programming/merge-files-in-column-output/26553.html).

Perhaps some day someone else has a nice use for this too.

First it counts the files (nr of files is used later on).
The files names without extension are listed in a file "list.dat".

@echo off 
SetLocal EnableDelayedExpansion
for /f  %%a in ('dir/b *.txt') do (
    set /a count+=1
    set /a count1=count-1
)
echo total is !count!
echo !count1!

rem empty contents of files
type nul > x.txt
type nul > y.txt
type nul > z.txt
type nul > list.dat

setlocal
set first=y
(
    for /f %%g in ('dir/b/a-d a*.txt') do (
        if defined first (
            set first=
            set/p=%%~ng <nul
        ) else (
            set/p=%%~ng <nul
        )
    )
)>>list.dat

for /f %%j in (list.dat) do (
    echo. %%j   
    for %%a in (%%j) do find /n /v "" < %%a.txt >> x.txt
)
sort x.txt /o x.txt

set "regex=^\[[0-9]\]"
:loop
findstr /r "%regex%" x.txt >> y.txt
if not errorlevel 1 (
    set "regex=^\[[0-9]%regex:~3%
    goto loop
)

set cnt=
set line=
for /f "delims=" %%a in (y.txt) do (
    set input=%%a
    set input=!input:*]=!
    set line=!line! !input!
    if "!cnt!"=="!count1!" (
        >> z.txt echo !line:~1!
        set line=
    )
    set /a cnt=^(cnt + 1^) %% !count!
)

type nul > zz.dat
for /F "delims=" %%i in (z.txt) do (
    set cnt=1
    set rrow=
    for %%j in (%%i) do (
        set /A cnt-=1
        if !cnt! equ 0 (set cnt=0 & set rrow=!rrow! %%j)
    )
    set cnt=2
    set row=
    for %%j in (%%i) do (
        set /A cnt-=1
        if !cnt! equ 0 (set cnt=2 & set row=!row! %%j)
    )
    set row=!row:~1!
    echo. !rrow! !row!>> zz.dat
)

del x.txt
del y.txt
pause
浮云落日 2024-12-12 18:31:07

我认为 BAT 编程不适合您想要完成的任务。您可能会发现一些复杂的解决方案,或者最终使用第三方工具来补充 BAT 编程(我立即想到了 SED),IMO 只会在方程式中添加另一个问题,要么强迫用户安装这样的工具,要么使您的程序复杂化BAT 的分发和安装具有相同的意图。

另一方面,使用任何通用编程语言进行编程来解决您的问题都是一项非常容易的任务。

所以,我会尝试 VB 或 javascript,它们几乎在所有 Windows 安装中都可用。看看这个并开始...

@set @junk=1 /*
@echo off
rem textcolumns text
cscript //nologo //E:jscript %0 %*
goto :eof
:allfiles
pushd %1
for /f %%a in ('dir /b /s *.txt') do
  call :coltxt %%a
)
goto :eof
:coltxt
cscript //nologo //E:jscript %*
goto :eof
*/


function openFile(fn) {
 var ForReading = 1, ForWriting = 2, ForAppending = 8;
 var TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0;
 var fso = new ActiveXObject("Scripting.FileSystemObject");
 // Create the file, and obtain a file object for the file.
 // fso.CreateTextFile(fn);
 var f = fso.GetFile(fn);
 // Open a text stream for input.
 ts = f.OpenAsTextStream(ForReading, TristateUseDefault);
 // Read from the text stream and display the results.
 return ts;
}


function removeFirstWord(s) {
  var p1=s.indexOf(" ");
  if (p1>0) {
    return s.substring(p1+1);
  } else {
    return new String();
  }
}

function getCol(ts) {
 var s;
 s = ts.ReadLine();
 s = removeFirstWord(s);
 return s;
}


// main 
x = WScript.Arguments;
fs = new Array(x.length);

for (var i=0; i<x.length; i++) {
 fs[i] = openFile(x(i));
}

while (!fs[0].AtEndOfStream) {
  var s = fs[0].ReadLine();
  for (var i=1; i<fs.length; i++) {
    s += getCol(fs[i]);
  }
  WScript.echo(s);
}

for (var i=0; i<fs.length; i++) {
  fs[i].close();
}

I don't think BAT programming is appropiate for what you want to acomplish. You might find some convoluted solution, or end up using a third party tool to complement BAT programming (SED comes immediately to my mind) would IMO only add another problem to the equation, either forcing the user to install such a tool, or complicating your BAT distribution and installation with the same intent.

On the other hand, solving your problem is a very easy task to program in any general purpouse programming language.

So, I would try either VB or javascript, which are available in almost all windows installations. Take a look at this and get started...

@set @junk=1 /*
@echo off
rem textcolumns text
cscript //nologo //E:jscript %0 %*
goto :eof
:allfiles
pushd %1
for /f %%a in ('dir /b /s *.txt') do
  call :coltxt %%a
)
goto :eof
:coltxt
cscript //nologo //E:jscript %*
goto :eof
*/


function openFile(fn) {
 var ForReading = 1, ForWriting = 2, ForAppending = 8;
 var TristateUseDefault = -2, TristateTrue = -1, TristateFalse = 0;
 var fso = new ActiveXObject("Scripting.FileSystemObject");
 // Create the file, and obtain a file object for the file.
 // fso.CreateTextFile(fn);
 var f = fso.GetFile(fn);
 // Open a text stream for input.
 ts = f.OpenAsTextStream(ForReading, TristateUseDefault);
 // Read from the text stream and display the results.
 return ts;
}


function removeFirstWord(s) {
  var p1=s.indexOf(" ");
  if (p1>0) {
    return s.substring(p1+1);
  } else {
    return new String();
  }
}

function getCol(ts) {
 var s;
 s = ts.ReadLine();
 s = removeFirstWord(s);
 return s;
}


// main 
x = WScript.Arguments;
fs = new Array(x.length);

for (var i=0; i<x.length; i++) {
 fs[i] = openFile(x(i));
}

while (!fs[0].AtEndOfStream) {
  var s = fs[0].ReadLine();
  for (var i=1; i<fs.length; i++) {
    s += getCol(fs[i]);
  }
  WScript.echo(s);
}

for (var i=0; i<fs.length; i++) {
  fs[i].close();
}
你在看孤独的风景 2024-12-12 18:31:07

如果所有文件都具有相同的长度:

for /f %i in ('find /c /v "" ^< 1.txt') do set n=%i

查找行数。

设置文件数量:

set f=4

然后读取&合并每一行:

for /l %b in (1,1,%n%) do (
set /p=l%b <nul
for /l %a in (1,1,%f%) do (
for /f "tokens=2" %i in ('find "l%b" ^< %a.txt') do (
set /p=%i <nul
))
echo:
)

示例输出:

l1 a1 b1 c1 d1
l2 a2 b2 c2 d2
l3 a3 b3 c3 d3

在 Win 10 CMD 上测试

示例输出

If all files have same length:

for /f %i in ('find /c /v "" ^< 1.txt') do set n=%i

To find number of lines.

Set number of files:

set f=4

Then read & merge each line:

for /l %b in (1,1,%n%) do (
set /p=l%b <nul
for /l %a in (1,1,%f%) do (
for /f "tokens=2" %i in ('find "l%b" ^< %a.txt') do (
set /p=%i <nul
))
echo:
)

Sample output:

l1 a1 b1 c1 d1
l2 a2 b2 c2 d2
l3 a3 b3 c3 d3

Tested on Win 10 CMD

Sample Output

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文