【问题标题】:How to add a line with a unique string to a file and a directory with that same string in bash如何在bash中将具有唯一字符串的行添加到文件和具有相同字符串的目录
【发布时间】:2019-07-29 22:31:47
【问题描述】:

我有一个几百行的 csv 文件。这些行中的每一行都以七个数字的某些标识符开头。在 bash 中,我需要为每个唯一标识符创建一个目录,并在每个目录中创建一个 csv 文件,其中包含以该唯一标识符开头的行。例如,对于我原始 csv 中的这一行:

7988114_lig2,c1cccc(Cl)c1CSc(n2)nn(c23)C(C4=C(N3)CCCC4=O)c5cccnc5,-6.18411530082281

我需要创建一个名为7988114 的目录和一个名为7988114.csv 的csv,然后将原始csv 中以7988114 开头的每一行复制到7988114.csv 中。

我已经编写了代码来创建具有正确名称的目录。速度不是一个大问题,所以我尝试了许多看似简单而迂回的方法来在适当的目录中创建 csv 文件并将正确的行放在这些 csv 文件中,但我并不精通 bash。任何帮助将不胜感激,谢谢!

【问题讨论】:

  • 请出示您目前拥有的代码。
  • 只有几百行?大约有多少种不同的标识符?
  • 有大约 50 个唯一标识符

标签: bash csv


【解决方案1】:

如果我了解您想要为每个唯一的 7 位 id(每行中的前 7 个字符)创建一个目录,并希望将所有以该 id 开头的行包含在该目录中名为“id. csv",您可以单独使用awk 做您需要的事情。只要您感兴趣的 ID 始终是该行的前 7 个字符,您就可以:

awk -F, '{
    id=substr($1, 1, 7)
    system("[ -d " id " ] ||  mkdir " id)
    print $0 > id "/" id ".csv"
}' file.csv

使用您的示例输入,它将创建目录 7988114 和文件 7988114.csv 包含整行,例如

$ cat 7988114/7988114.csv
7988114_lig2,c1cccc(Cl)c1CSc(n2)nn(c23)C(C4=C(N3)CCCC4=O)c5cccnc5,-6.18411530082281

具有相同id 的所有行都将附加到同一文件中,从而为每个唯一的id 创建一个目录和一个名为“id.csv”的文本文件,其中包含该唯一@ 的所有行987654330@.

【讨论】:

    【解决方案2】:

    带有 for-each 循环的 4 行 bash 脚本。对于原始文件中的每一行,从开头切掉标识符,然后在原始文件中找到所有匹配的行并保存。

    #!/bin/bash
    for line in `cat original.csv`; do
        filename="${line%%_*}"
        cat original.csv | grep $filename > $filename/$filename.csv
    done
    

    由于重复行将完成相同的工作,因此效率略低,但 bash 脚本往往不太关注执行速度,而更多关注速度和创建的简单性。

    【讨论】:

    • 对于未来的读者来说,这个答案也非常适合我的需求,但是当我将它添加到我的脚本时,它比接受的答案慢了大约三分之一。
    • 阅读有关 UUOC 奖(猫的无用使用)。你可以写grep "$filename" original.csv。祝大家好运。
    【解决方案3】:

    假设没有那么多唯一标识符,每个标识符打开一个文件会使您达到进程可以打开的文件数量的限制,这个 perl 脚本应该可以解决问题:

    #!/usr/bin/env perl
    use warnings;
    use strict;
    use autodie;
    
    my %files;
    
    while (<>) {
      if (/^(\d{7})/) {
        my $id = $1;
        unless (exists $files{$id}) {
          mkdir $id;
          open $files{$id}, ">", "$id/$id.csv";
        }
        my $fh = $files{$id};
        print $fh $_;
      } else {
        warn "Invalid line $_";
      }
    }
    

    【讨论】:

      【解决方案4】:
      #!/bin/bash
      file=test.csv
      
      while -r read line ;do
       id="${line%%_*}"
       [[ -d "$id" ]] && continue #already processed
       mkdir "$id"
       grep -E "^$id" "$file" > "$id/$id.csv"
      done < "$file"
      

      但如果你关心速度,awk 应该比 bash 快。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-06-18
        • 1970-01-01
        • 2015-09-08
        • 2022-10-14
        • 2015-01-18
        • 1970-01-01
        • 2019-01-12
        相关资源
        最近更新 更多