我希望创建一系列文本文件,每个文本文件包含输入文件第 1 列中的逗号分隔值列表,基于输入文件第 2 列中的共享值。
输入文件格式:
CB-03-01-01 CB-03.1
CB-03-01-02 CB-03.1
CB-03-01-03 CB-03.1
CB-03-02-01 CB-03.2
CB-03-02-02 CB-03.2
CB-03-02-03 CB-03.2
CB-08-01 CB-08
CB-08-02 CB-08
CB-08-03 CB-08
所需输出:CB-03.1.txt
CB-03-01-01,CB-03-01-02,CB-03-01-03
CB-03.2.txt
CB-03-02-01,CB-03-02-02,CB-03-02-03
CB-08.txt
CB-08-01,CB-08-02,CB-08-03
感谢您的任何帮助,您可以提供!
答案1
您可以使用的命令是:
awk '{a[$2]=a[$2]","$1} END {for(i in a) print substr(a[i],2) >i".txt"}' input_file
a
是关联数组,substr
函数从数组元素的第一个赋值中删除前导逗号。
根据评论,您可能需要替换>i".txt"
为>(i".txt"); close(i".txt")
某些版本awk
并关闭打开的文件处理程序
答案2
使用乐(以前称为 Perl_6)
~$ raku -e 'my %h; for lines() { %h.push: .[1] => .[0] given .split(/ \s+ /) };
for %h.sort() {
spurt( ( .key ~ ".txt" ).IO, $_.value.join(",") ~ "\n", createonly => True);
};' file.txt
上面是用 Raku 编码的解决方案,Raku 是 Perl 编程语言家族的成员。 Raku 的一个优势是对 Unicode 的高级支持。
基本上,所述问题是key
/value
问题,其中所有键/值对都存储在%h
哈希中。每次看到新的第二列(文本)元素时,您都会创建一个key
,并将相应的第一列(文本)元素添加为value
。由于keys
在哈希中保持唯一,因此value
相同的后续 skey
会被push
ed (或append
ed)到相同的key
。
您可以编写下面的代码,其中硬编码了适当的路径,而不是从命令行获取输入:
~$ raku -e 'my $in = "/path/to/file.txt".IO; my %h;
for $in.lines() { %h.push: .[1] => .[0] given .split(/ \s+ /) };
for %h.sort() {
my $out = IO::Spec::Unix.catpath($, $in.dirname, .key) ~ ".txt";
spurt( $out, $_.value.join(",") ~ "\n", createonly => True) };'
其他选项包括将上面的代码(单引号内)保存为脚本,并在命令行中使用raku script.raku
.请注意,如上所述,只需IO::Spec
根据需要更改调用(更改为IO::Spec::Win32
、IO::Spec::Cygwin
等),即可将硬编码脚本移植到其他操作系统。
https://docs.raku.org/language/hashmap#Mutable_hashes_and_immutable_maps
https://docs.raku.org/routine/split
https://raku.org
答案3
使用任何 awk(未经测试):
awk '
$2 != prev {
if ( out != "" ) {
print "" > out
close(out)
}
out = $2 ".txt"
sep = ""
prev = $2
}
{
printf "%s%s", sep, $1 > out
sep = ","
}
END {
if ( out != "" ) {
print "" > out
}
}
' file
上面的代码一次只打开 1 个输出文件,因此不会遇到“打开文件太多”错误(或速度变慢),并且一次只在内存中存储 1 行,因此无论如何它都会继续工作您的输入文件很大。
$2
它确实假设您的输入按您提供的示例中的值进行分组,但如果您的实际数据不是这种情况,则只需首先按第二个字段对其进行排序,例如sort -k2,2 file | awk 'script'
。