![递归批处理文件](https://linux22.com/image/1334821/%E9%80%92%E5%BD%92%E6%89%B9%E5%A4%84%E7%90%86%E6%96%87%E4%BB%B6.png)
我有一个如下所示的文件:
head1,head2,head3,head4,head5,head6
a11,a12,keyA,a14,a15,a16
a21,a22,keyB,a24,a25
a31,a32,keyC,a34
a41,a42,keyB,a44,a44
a51,a52,keyA,a54,a55,a56
a61,a62,keyA,a64,a65,a66
a71,a72,keyC,a74
some message
目标:将唯一键列表写入文本文件。例如,上述文件的结果应为:
键 A、键 B、键 C
这是我想在批处理文件中实现的伪代码recur.bat
- 读取输入文件的第二行
- 如果第二行不存在键,则返回,否则继续
- 附加
keyX
到列表 FINDSTR /v keyX inputfile
- 将结果传输至
recur.bat
我不知道这是否是在不使用实际编程语言的情况下实现这一目标的最有效方法。
对于实际批处理文件代码有什么建议吗?
答案1
单独回答,因为这本质上是一个不同的解决方案
因此,这是一个 cmd/batch 版本。
@echo off
type NUL>output.txt
for /f "tokens=1,3 delims=, skip=1" %%a in (input.txt) do (
if "%%b"=="" goto :eof
findstr "^%%b$" output.txt > NUL
if ERRORLEVEL 1 echo %%b>>output.txt
)
它创建 output.txt,然后使用for
和,
作为分隔符读取 input.txt。第一行被跳过。
tokens=1,3
需要读取第一个标记( )才能在该some message
行上停止它,因为如果请求的标记(tokens=3
)不存在,它就会跳过该行并继续 - 并且永远不会运行if
。%%a
是第一个请求的标记(1
),%%b
是第二个(3
)。
a71,a72,a73,a74
a71,a72,keyC,a74
some message
a71,a72,keyD,a74
keyD
不会被读取,因为它在前一行停止(没有第三个标记)。但是,a73
会被计算在内。
这用于findstr
检查输出文件上的键是否已存在 - 效率很低,但有效。使用 RegEx 确保匹配整行;如果一个键完全包含在另一个键内,则不会匹配(即不会匹配keyA
)key
。输出通过管道传输以NUL
保持安静。
如果密钥不在输出文件中,它将附加该密钥。
答案2
您可以使用 Windows Vista 或更高版本附带的 PowerShell:
$keys = @( );
Import-Csv input.txt | ForEach-Object {
if (!$_.head3) {
$keys | Out-File output.txt;
break;
} else {
if (!($keys -contains $_.head3)) {
$keys += $_.head3;
}
}
}
对于大量数据,这种方法可能会比较慢,因为它使用数组 ( $keys
) 来保存和检查唯一键。另一种方法是将所有内容写入文本文件,对其进行排序,然后通过 运行Get-Unique
。另一种方法是使用哈希表(对内存使用没有帮助,但比检查数组中是否存在某些内容要快)。
这将使用Import-Csv
,它将以第一行作为标题。然后它将对象(行)的数组传递给ForEach-Object
。$_
是引用每个对象(行)的变量。.head3
是名称为 的属性head3
,如示例数据中定义为包含键的列。它会检查此行中此列是否有值;如果没有,它会输出到文件并按照您的伪代码退出。请注意,非键值也可能被接受。如果您对密钥有/需要更严格的规则,您可以检查长度,或者进行一些 RegEx 模式匹配等。
a71,a72,a73,a74
a71,a72,keyC,a74
some message
a71,a72,keyD,a74
目前,a73
算作一个键(它在第三列, )。由于它没有第三列,head3
程序将在 处结束,并且不会读取。some message
keyD
如果该行确实有一个键列,它会检查该键是否已经存在于数组中,如果不存在,则添加它。请注意-contains
不区分大小写。如果这是一个问题,那么可以进行更改。
因此,您可能需要用正确的名称替换input.txt
output.txt
和head3
。这是最简单的解决方案,不会修改数据的顺序,但如果需要,也可以使用更快的解决方案。
答案3
在 Bash 中(如果你使用的是 Windows,则可以使用 Cygwin),这很容易:
1.)将 , 替换为换行符(\n)
sed -i 's/,/\n/g' superuser.txt
之前你有:
head1,head2,head3,head4,head5,head6 a11,a12,keyA,a14,a15,a16 a21,a22,keyB,a24,a25 a31,a32,keyC,a34 a41,a42,keyB,a44,a44 a51,a52,keyA,a54,a55,a56 a61,a62,keyA,a64,a65,a66 a71,a72,keyC,a74
现在你有:
head1
head2
head3
head4
head5
head6 a11
a12
keyA
a14
a15
a16 a21
a22
keyB
a24
a25 a31
a32
keyC
a34 a41
a42
keyB
a44
a44 a51
a52
keyA
a54
a55
a56 a61
a62
keyA
a64
a65
a66 a71
a72
keyC
a74
2.) 搜索“key”,对结果进行排序并删除重复项
grep -F key superuser.txt | sort | uniq
给你:
keyA
keyB
keyC