Bash (拆分) 文件名比较失败



在我的目录中,我有文件(*fastq.gz.fasta)和目录,其名称包含文件名(*fastq.gz.fasta-blastdb):

IVC6_Meino.clust.gz.fasta-blastdb  
IVC5_Mehiv.clust.gz.fasta-blastdb  
....  
IVC6_Meino.clust.gz.fasta  
IVC5_Mehiv.clust.gz.fasta  
....  

在 bash 脚本中,我想使用后者上的 cut 选项将文件名与 direcories 进行比较,以仅提取文件名部分。如果这两个名称匹配,我想做进一步的事情(现在分别是回显匹配或不匹配)。 我写了以下一段代码:

#!/bin/bash
for file in *.fasta
do
for db in *-blastdb
do
echo $file, $db | cut -d '-' -f 1
if [[ $file = "$db | cut -d '-' -f 1" ]]; then
echo "match"
else
echo "no match"
fi
done
done

但它不会检测匹配项。输出如下所示:
...

IVC6_Meino.clust.gz.fasta, IIIA11_Meova.clust.gz.fasta  
no match  
IVC6_Meino.clust.gz.fasta, IVC5_Mehiv.clust.gz.fasta  
no match  
IVC6_Meino.clust.gz.fasta, IVC6_Meino.clust.gz.fasta  
no match  

如您所见,最后一行应为匹配,字符串看起来相同。 我错过了什么?

您可以使用参数扩展更轻松地执行此操作:

for file in *.fasta
do
for db in *-blastdb
do
echo "$file", "$db"         
if [[ "${file%%.fasta}" = "${db%%.fasta-blastdb}" ]]; then
echo "match"
else
echo "no match"
fi
done
done

如果你想修复你的问题,问题是使用$db | cut -d '-' -f 1有了echo,似乎echo正在打印管道。其实不然。cut正在打印。当你这样做[[ $file = "$db | cut -d '-' -f 1" ]]它相当于[[ $file = [return code from last pipe component] ]]

您需要使用$(..)shell 构造来捕获管道的输出,并且需要echo以获取启动管道的$db的内容。您应该引用"$db"这样您就不会从变量的内容中进行单词拆分或通解。

这样:

for file in *.fasta
do
for db in *-blastdb
do
ts=$(echo "$db" | cut -d '-' -f 1)
echo "$file", "$ts"
if [[ "$file" = "$ts" ]]; then
echo "match"
else
echo "no match"
fi
done
done             # this works I think -- not tested...

请谨慎引用Bash并自由使用ShellCheck。


您拥有的结构也不是最有效的。您将为*-blastdb中的每个文件循环访问一次*-blastdbglob。如果您有很多文件,可能会变得非常慢。

为了解决这个问题,你可以用 Bash 数组重写这个循环(如果你有 Bash 4+ 最好)或使用awk

ext1=.fasta
ext2=.fasta-blastdb
awk  'FNR==NR{
s=$0
sub("\"ext1"$","",s)
seen[s]=$0
next}
{
s=$0
sub("\"ext2"$","",s)
if (s in seen)
print seen[s], $0
}
' ext1="$ext1" ext2="$ext2" <(for fn in *$ext1; do echo "$fn"; done) <(for fn in *$ext2; do echo "$fn"; done)

每个 glob 只执行一次,awk使用数组来测试基本名称是否相同。

最好

最新更新