【问题标题】:Outputting values into csvs - command line将值输出到 csvs - 命令行
【发布时间】:2013-09-22 16:11:19
【问题描述】:

这个网站的新手和一般的编程(生物学家背景)。

无论如何,我的任务是获取文本文件名、计算唯一行数、计算总行数并将其输出到 csv 文件中。这是我在 Cygwin 中使用的代码

#!/bin/bash
file=./data/*.txt
name= ls ./data > output.csv
unique= sort $file | uniq | wc -l >> output.csv
total= cat $file | wc -l >> output.csv
nano output.csv

我得到了所有正确的输出,我的问题是:

  1. 我可以选择在哪一列输入每个值吗?目前它们被直接添加在彼此下方。

  2. 有没有更有效的方法将输出添加到输出文件?

谢谢!

弗兰

【问题讨论】:

  • 谢谢乔纳森,我是一个非常随意的用户,所以仍然没有足够的投票权。请放心,我很快就会:)

标签: bash csv command-line


【解决方案1】:

没有人可以与 Jonathan Leffler 竞争,但以下 gawk 脚本也可以满足您的要求。它的代码有点多,但在有多个文件的情况下,它可能比 shell 脚本更有效。

#!/usr/local/bin/gawk -f

function show() {
  print last,length(unique),total;
  last=FILENAME;
  delete(unique);
  total=0;
}

BEGIN {
  OFS=",";
}

NR==1 {
  last=FILENAME;
}

FILENAME != last {
  show();
}

{
  total++; unique[$0];
}

END {
  show();
}

这里唯一新颖的是unique[] 数组的使用。由于 awk 的数组都是关联的,因此使用 $0 作为键会生成一个长度为唯一行数的数组。并且仅仅引用一个数组元素会导致它存在,所以你实际上不需要设置 unique[$0] 到任何东西。

要使用该脚本,您可以使用如下命令行:

$ ./script.sh one.txt two.txt > output.csv

或者类似

$ ./script.sh *.txt > output.csv

请注意,在 Cygwin 中,您可能需要显式安装 gawk 包,并且您需要在脚本的第一行调整 gawk 的路径。您可以输入 which gawk 以查看它是否已安装,如果已安装,它在您的系统中的位置。

【讨论】:

    【解决方案2】:

    对现有代码进行了许多改进,即:

    #!/bin/bash
    file=./data/*.txt
    name= ls ./data > output.csv
    unique= sort $file | uniq | wc -l >> output.csv
    total= cat $file | wc -l >> output.csv
    nano output.csv
    

    写入output.csv 的三行代码小心地将环境变量nameuniquetotal 设置为空字符串,然后运行命令——这并不是完全错误,但确实不是你所拥有的记住,要么。 sort | uniq 可以简化为 sort -u。当wc -l < $file 用更少的进程完成同样的工作时,就不需要cat $file | wc -lls 行正在生成与通配符扩展相同的名称。一次一个文件与所有文件一起存在一些问题。

    如果您想要一个 CSV 文件,其中包含每个文件的名称、唯一行和总行数,那么我们希望在代码中看到一个循环。

    for file in ./data/*.txt
    do
        unique=$(sort -u $file | wc -l)
        total=$(wc -l < $file)
        echo "$file,$unique,$total"
    done
    

    这将运行 sort -u 以唯一排序(不需要显式的 uniq),并捕获来自 wc -l 的输出。它使用来自文件的标准输入运行wc -l,以获得总行数;使用 I/O 重定向会阻止 wc 打印文件名。然后回显打印数据。如果您只想要文件的基本名称(只是xyz.txt 而不是./data/xyz.txt),那么您可以在echo 中修复它:

    echo "$(basename $file),$unique,$total"
    

    或:

    echo "${file##*/},$unique,$total"
    

    唯一可能的缺点是它对每个文件运行一次命令,如果有很多文件,这可能会有点问题。不过,这会奏效——先把它做好,然后,如果有速度问题,花时间优化它。

    【讨论】:

    • 谢谢你,你对变量名是完全正确的。我正在修改输出为echo $v1, $v2, $v3 的不完整代码块,并忘记了当更改为作为文件输出时不再需要它们。我发现 cat 是删除 wc 添加路径所必需的(这是我不想要的)。在这种情况下,包含该文件的文件夹仅包含一个文件,因此我不需要 for 循环,但下一个练习是针对文件夹中的多个文件,我使用了类似于您描述的内容。再次感谢!
    猜你喜欢
    • 2014-04-08
    • 2013-06-10
    • 1970-01-01
    • 2020-10-12
    • 2018-08-18
    • 2014-10-26
    • 2014-05-15
    • 1970-01-01
    • 2013-06-08
    相关资源
    最近更新 更多