批处理:将列中的文本文件合并

时间:2011-09-22 19:14:57

标签: loops batch-file

我正在尝试将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

尝试1的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======================================

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

这种尝试(2/3)最终会给出我想要的东西:

::=============================================
@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的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!x %% a!对于每个文件,将其打印在单独的列中。

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

set /P line1=< hmm.txt

然后

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

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

任何人都有解决方案吗?

3 个答案:

答案 0 :(得分:1)

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

也许有一天,其他人对此也有很好的用处。

首先它计算文件(稍后使用文件的nr)。 没有扩展名的文件名列在文件“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

答案 1 :(得分:1)

我认为BAT编程不适合您想要实现的目标。您可能会发现一些复杂的解决方案,或最终使用第三方工具来补充BAT编程(SED立即出现在我的脑海中)IMO只会在方程式中添加另一个问题,要么强制用户安装此类工具,要么使您的工作复杂化BAT的分配和安装具有相同的意图。

另一方面,使用任何通用purpouse编程语言编程是一项非常容易的任务。

所以,我会尝试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();
}

答案 2 :(得分:0)

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

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上测试

Sample Output