我想制作一个 bash 脚本(split.sh),它迭代具有相同后缀的多个目录,然后针对其中的特定文件运行一个函数。我快到了:
#!/bin/bash
path="/mypath/MAP-9-[0-9][0-9][0-9]"
for filename in $path/*bam; do
[ -e "$filename" ] || continue
echo $filename
for chrom in `seq 1 22` X Y
do
samtools view -bh $filename $chrom > $path/$chrom.bam
samtools index > $path/$chrom.bam;
done
done
但是,我收到很多此类消息:“split.sh:第 12 行:/mypath/MAP-9-[0-9][0-9][0-9]/6.bam:没有这样的文件或目录”
问题是脚本无法识别路径名的“[0-9][0-9][0-9]”正则表达式部分。我还尝试在方括号中添加转义字符,但没有成功。这一定是一个非常简单的解决方案,但我无法解决它。
这是 tree 命令输出的摘录:
|-- [[
|-- MAP-9-001
| |-- MAP-9-001.bam
| `-- MAP-9-001.bam.bai
|-- MAP-9-003
| |-- MAP-9-003.bam
| `-- MAP-9-003.bam.bai
|-- MAP-9-005
| |-- MAP-9-095.bam
| `-- MAP-9-095.bam.bai
|-- split.sh
答案1
不要与glob
vs regex
(您glob
在此处使用的)混淆:
Glob 是 shell 模式,可用于匹配字符串或扩展路径名:
[[ $name = Bob* ]]
rm *.txt
看http://mywiki.wooledge.org/glob
脚本的更正版本:
#!/bin/bash
for filename in /path/MAP-9-[0-9][0-9][0-9]/*bam; do
[[ -e $filename ]] || continue
echo "$filename"
for chrom in {1..22} X Y; do
samtools view -bh "$filename" "$chrom" > "$(dirname "$filename")/$chrom.bam"
samtools index "$(dirname "$filename")/$chrom.bam"
done
done
学习如何在shell中正确引用,这非常重要:
“双引号”包含空格/元字符的每个文字以及每一个扩张:
"$var"
,"$(command "$var")"
,"${array[@]}"
,"a & b"
。用于'single quotes'
代码或文字$'s: 'Costs $5 US'
,ssh host 'echo "$HOSTNAME"'
.看
http://mywiki.wooledge.org/Quotes
http://mywiki.wooledge.org/Arguments
http://wiki.bash-hackers.org/syntax/words
何时需要双引号
[[
是一个 bash 关键字,类似于(但比)[
命令更强大。看http://mywiki.wooledge.org/BashFAQ/031和http://mywiki.wooledge.org/BashGuide/TestsAndConditionals。除非你是为 POSIX sh 编写,否则我建议[[
答案2
/mypath/MAP-9-[0-9][0-9][0-9]/*.bam
是一个 shell glob,或者文件名扩展表达。它扩展为匹配文件列表 - 您可以使用它来迭代输入文件,但您不能指望它作为“每次迭代”通配符来生成相应的输出文件。我认为您可能想要的是从相应的循环变量生成每个输出文件$filename
,如下所示:
#!/bin/bash
shopt -s nullglob
for filename in /mypath/MAP-9-[0-9][0-9][0-9]/*.bam; do
[ -e "$filename" ] || continue
echo "$filename"
for chrom in {1..22} X Y; do
samtools view -bh "$filename" "$chrom" > "${filename%/*}/${chrom}.bam"
samtools index > "${filename%/*}/$chrom.bam"
done
done
贝壳参数扩展 ${filename%/*}
扩展为 的值$filename
并删除最短的尾随子字符串/*
;因此,它为您提供每个输入文件的目录名,然后您可以在其中添加 来$chrom.bam
依次形成每个输出文件。