此网站的新功能和一般编程(生物学家的背景)。
无论如何,我有一个任务是获取文本文件名,计算唯一行,计算总行数并将其输出到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
我得到了所有正确的输出,我的问题是:
我可以选择输入每个值的列吗?目前,它们直接相互添加。
是否有更有效的方法将输出添加到输出文件?
谢谢!
弗兰
答案 0 :(得分:3)
现有代码有许多改进,包括:
#!/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
的三行仔细设置环境变量name
,unique
和total
以清空字符串,然后运行命令 - 这不是错误的,但你真的不是想到的。 sort | uniq
可以简化为sort -u
。当cat $file | wc -l
只用少一个进程执行相同的工作时,不需要wc -l < $file
。 ls
行生成的名称与通配符扩展名称相同。你一次有一个文件与所有文件一起出现问题。
如果您想要一个包含每个文件的名称,唯一行和总行的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"
唯一可能的缺点是它每个文件运行一次命令,如果有很多文件,这可能会有点问题。但是,这将起作用 - 首先正确,只有在遇到速度问题时才花时间进行优化。
答案 1 :(得分:2)
没有人可以与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
以查看它是否已安装,如果已安装,则可以在系统上的位置。