计算目录中名称具有特定字符串的文件数量?

计算目录中名称具有特定字符串的文件数量?

我有以下文件:

Codigo-0275_tdim.matches.tsv  
Codigo-0275_tdim.snps.tsv  
FloragenexTdim_haplotypes_SNp3filter17_single.tsv  
FloragenexTdim_haplotypes_SNp3filter17.tsv  
FloragenexTdim_SNP3Filter17.fas  
S134_tdim.alleles.tsv    
S134_tdim.snps.tsv  
S134_tdim.tags.tsv

snp我想计算名称中包含单词(区分大小写)的文件数量。我尝试使用

grep -a 'snp' | wc -l   

但后来我意识到grep在文件中进行搜索。扫描文件名的正确命令是什么?

答案1

snp您的意思是要在文件中搜索名字?这将是一个简单的 shell glob(通配符),使用方式如下:

ls -dq *snp* | wc -l

-q如果您的版本ls无法识别该标志,请忽略该标志。它处理包含“奇怪”字符(包括换行符)的文件名。

答案2

如果你静静地站在 Unix&Linux 的走廊里仔细听,你会听到一个幽灵般的声音,可怜兮兮地哀号:“文件名中包含换行符怎么办?”

ls -d *snp* | wc -l

或者,同等地,

printf "%s\n" *snp* | wc -l

将输出包含 的所有文件名snp,每个文件名后跟一个换行符, 但还包括文件名中的任何换行符,然后计算输出中的行数。如果有一个文件名为

                                f o o s n p \n b a r . t s v

那么这个名字将被写成

foosnp
bar.tsv

当然,这将被视为两条线。

有一些替代方案至少在某些情况下效果更好:

printf "%s\n" * | grep -c snp

它计算包含 的行snp,因此foosnp(\n)bar.tsv上面的示例仅计算一次。对此略有不同的是

ls -f | grep -c snp

上面两个命令的不同之处在于:

  • ls -f包含名称以.;开头的文件。printf … *除非dotglob设置了 shell 选项,否则不会。
  • printf是一个内置的 shell;ls是一个外部命令。因此,ls可能会使用稍多的资源。
  • 当 shell 处理 a 时*,它会对文件名进行排序; ls -f不对文件名进行排序。因此,ls使用的资源可能会稍微少一些。

但它们有一些共同点:当文件名包含换行符时,它们都会给出错误的结果并且snp在换行符之前和之后都有

其他:

filenamelist=(*snp*)
echo ${#filenamelist[@]}

这将创建一个 shell 数组变量,列出包含 的所有文件名snp,然后报告数组中的元素数量。文件名被视为字符串,而不是行,因此嵌入的换行符不是问题。可以想象,如果目录很大,这种方法可能会出现问题,因为文件名列表必须保存在 shell 内存中。

完后还有:

早些时候,当我们说 时printf "%s\n" *snp*,该命令为 扩展中的每个参数printf重复(重用)一次格式字符串。在这里,我们做了一个小小的改变:"%s\n"*snp*

printf "%.0s\n" *snp* | wc -l

这将为."%.0s\n"扩展中的每个参数重复(重用)一次格式字符串*snp*。但"%.0s"意味着打印每个字符串的前零个字符——即什么也不打印。该命令将为名称中printf包含的每个文件仅输出一个换行符(即空行) ;snp然后wc -l会计算它们。并且,您可以.通过设置包含这些文件dotglob

答案3

抽象的:

适用于具有“奇数”名称(包括换行符)的文件。

set -- *snp* ; echo "$#"                             # change positional arguments

count=$(printf 'x%.0s' *snp*); echo "${#count}"      # most shells

printf -v count 'x%.0s' *snp*; echo "${#count}"      # bash

描述

由于一个简单的 glob 将匹配snp其名称中的每个文件名echo *snp*,对于这种情况,一个简单的文件就足够了,但为了真正表明只有三个文件匹配,我将使用:

$ ls -Q *snp*
"Codigo-0275_tdim.snps.tsv"  "foo * bar\tsnp baz.tsv"  "S134_tdim.snps.tsv"

剩下的唯一问题是计算文件数。是的,grep 是一种常用的解决方案,是的,用 来计算新行wc -l也是一种常用的解决方案。请注意,grep -c(count) 实际上计算一个字符串匹配的次数snp,并且,如果一个文件名的名称中包含多个snp字符串,则计数将不正确。

我们可以做得更好。

一种简单的解决方案是设置位置参数:

$ set -- *snp*
$ echo "$#"
3

为了避免更改位置参数,我们可以将每个参数转换为一个字符并打印结果字符串的长度(对于大多数 shell):

$ printf 'x%.0s' *snp*
xxx

$ count=$(printf 'x%.0s' *snp*); echo "${#count}"
3

或者,在 bash 中,避免使用子 shell:

$ printf -v count 'x%.0s' *snp*; echo "${#count}"
3

文件列表

文件列表(来自原始问题,其中添加了换行符):

a='
Codigo-0275_tdim.matches.tsv
Codigo-0275_tdim.snps.tsv
FloragenexTdim_haplotypes_SNp3filter17_single.tsv
FloragenexTdim_haplotypes_SNp3filter17.tsv
FloragenexTdim_SNP3Filter17.fas
S134_tdim.alleles.tsv
S134_tdim.snps.tsv
S134_tdim.tags.tsv'
$ touch $a

touch $'foosnp\nbar.tsv' 

这将有一个中间有一个换行符的文件:

f o o s n p \n b a r . t s v

并测试全局扩展:

$ touch $'foo * bar\tsnp baz.tsv'

这将添加一个星号,如果不加引号,它将扩展到整个文件列表。

答案4

假设您想计算 html 文件的数量:

ls | grep ".html" | wc -l

因此,如果您要计算“snp”的出现次数:

ls | grep "snp" | wc -l

相关内容