在bash中的for循环中,将wc-l的输出除以4



我正在尝试编写一个for循环,该循环解压缩文件名中包含R1的fastq.gz文件,确定每个文件中的行数,并将行数除以4。理想情况下,我也可以把它写进一个有两列的txt文件(文件名和行数/4(。

此循环解压缩R1 fastq文件,并确定每个文件中的行数,但不除以4(或将输出保存到txt文件中(。

for i in $(ls ./*R1*);
do
gzcat ./$i | wc -l
done;

这里的其他帖子建议在bash中使用bc进行划分,但我还没能将其集成到一个循环中。

您从不使用for i in $(ls anything),请参阅Bash Pitfalls#1。对于带有空格或任何其他特殊字符的文件名,循环将失败。在大多数情况下,您只需迭代使用for i in path/*; do ...的文件,但要明白,如果文件名中包含'n'字符作为名称的一部分,则可能会失败。处理所有文件名的最佳方法是使用find作为while read -r name; do ... done < <(find path -type f -name "*.gz")(注意进程替换< <(...)是一个仅bash的构造,如果使用POSIX shell,则管道到循环(

接下来,要将名称和行数/4写入一个新文件,请将整个循环封装在{ .... }之间的新范围中,然后一次将所有输出重定向到新文件。

您还应该添加验证来检查文件是否是以gz结尾的目录,并跳过任何找到的目录,以及跳过任何空文件(零文件大小(

如果你完全这样做,你可以做这样的事情:

{
for i in R1/*.gz; do
[ -d "$i" ] && continue                 ## skip any directories
[ -s "$1" ] && continue                 ## skip empty files
nlines=$(gzcat "$i" | wc -l)            ## get number of lines
printf "%st%sn" "$i" $((nlines / 4))  ## output name, nlines / 4
done
} > newfile         ## redirect all output to newfile

(输出用tab字符"t"分隔名称和数字/4-根据需要进行调整(

仔细看看,如果你有任何问题,请告诉我。

执行整数运算的最简单方法是使用$((...))表示法,正如您从以下简单示例中看到的:

Prompt> echo $((2*6))
12
Prompt> echo $((20/4))
5
Prompt> echo $((21/4))
5

它也可以与其他命令组合使用,如wc -l:

Prompt> cat .viminfo | wc -l
287
Prompt> echo $(($(cat .viminfo | wc -l) / 4))
71

我知道那些生物信息学数据集是巨大的,但如果你遇到一个少于1024行的数据集,那就简单地说:

% [g/n/m]awk 'BEGIN{ 
_ = system("exit $(( 977 / 4 )) ")
print _ }'
244

这是一种超懒惰的做事方式,它利用了256典型的退出代码这一事实,这是system()函数唯一愿意返回的东西——

这样,就不需要涉及getline和关闭命令和管道的所有额外开销。

如果允许5/4=1(四舍五入到最接近的整数(,这将起作用。如果你想使用小数(5/4=1.25(,那么你需要bcawk

for i in $(ls ./R1); do 
nb_lines=$(gzcat ./$i | wc -l)
echo $((nb_lines / 4))
done;

最新更新