根据命令行第二列中的共享值创建文本文件,其中包含一列中的逗号分隔值列表

根据命令行第二列中的共享值创建文本文件,其中包含一列中的逗号分隔值列表

我希望创建一系列文本文件,每个文本文件包含输入文件第 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会被pushed (或appended)到相同的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::Win32IO::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'

相关内容