我有以下文件:
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
Run Code Online (Sandbox Code Playgroud)
我想计算snp
名称中包含单词(区分大小写)的文件数量。我尝试使用
grep -a 'snp' | wc -l
Run Code Online (Sandbox Code Playgroud)
但后来我意识到grep
在文件中搜索。扫描文件名的正确命令是什么?
roa*_*ima 25
您的意思是要snp
在文件名中搜索吗?那将是一个简单的 shell glob(通配符),像这样使用:
ls -dq *snp* | wc -l
Run Code Online (Sandbox Code Playgroud)
-q
如果您的版本ls
无法识别该标志,请忽略该标志。它处理包含“奇怪”字符(包括换行符)的文件名。
如果你静静地站在Unix&Linux的走廊上仔细聆听,你会听到一个鬼魅般的声音,凄厉的哀号:“文件名有换行怎么办?”
ls -d *snp* | wc -l
Run Code Online (Sandbox Code Playgroud)
或者,等效地,
printf "%s\n" *snp* | wc -l
Run Code Online (Sandbox Code Playgroud)
将输出包含 的所有文件名snp
,每个文件名后跟一个换行符,
但还包括文件名中的任何换行符,然后计算输出中的行数。如果有一个文件名是
f o o s n p \n b a r . t s v
那么这个名字将被写成
foosnp
bar.tsv
Run Code Online (Sandbox Code Playgroud)
当然,这将被算作两行。
有一些替代方案至少在某些情况下效果更好:
printf "%s\n" * | grep -c snp
Run Code Online (Sandbox Code Playgroud)
它计算包含 的行snp
,所以foosnp(\n)bar.tsv
上面的例子只计算一次。对此略有不同的是
ls -f | grep -c snp
Run Code Online (Sandbox Code Playgroud)
上述两个命令的不同之处在于:
ls -f
将包括文件名称开头.
; 对printf … *
不对,除非dotglob
外壳选项设置。printf
是一个内置的 shell;ls
是外部命令。因此,ls
可能会使用更多的资源。*
,它会对文件名进行排序;
ls -f
不对文件名进行排序。因此,ls
可能会使用较少的资源。但它们有一些共同点:当文件名包含换行符并且snp
在换行符前后都有时,它们都会给出错误的结果。
其他:
filenamelist=(*snp*)
echo ${#filenamelist[@]}
Run Code Online (Sandbox Code Playgroud)
这将创建一个 shell 数组变量,列出包含 的所有文件名,snp
然后报告数组中的元素数。文件名被视为字符串,而不是行,因此嵌入的换行符不是问题。可以想象,如果目录很大,这种方法可能会出现问题,因为文件名列表必须保存在 shell 内存中。
早些时候,当我们说 时printf "%s\n" *snp*
,该printf
命令"%s\n"
为 的扩展中的每个参数重复(重用)一次格式字符串*snp*
。在这里,我们做了一个小改动:
printf "%.0s\n" *snp* | wc -l
Run Code Online (Sandbox Code Playgroud)
这将为."%.0s\n"
扩展中的每个参数重复(重用)格式字符串一次*snp*
。但是"%.0s"
意味着打印每个字符串的前零个字符——即,什么也不打印。该printf
命令将只输出一个包含snp
在其名称中的文件的换行符(即空行);然后wc -l
会计算它们。同样,您可以.
通过设置包含文件dotglob
。