我正在为一个小型管道处理数组作业,碰巧需要一种根据文件大小执行特定命令的方法。我找到了这篇文章和类似的文章,它们描述了如何做到这一点。目前我正在使用以下内容:
find $d/*.fasta -size +100M -exec sh -c '
chromap -i -r $1 -o $1.index
chromap --preset hic -x $1.index -r $1 -1 $d/hi-c/${ID}_1.fq.gz -2 $d/hi-c/${ID}_2.fq.gz --SAM -o /dev/stdout -t 48 | \
samtools view -bS -@ 48 | samtools sort -n -@ 48 | samtools view -h | sed -e "s/\/.//" | samtools view -bS -o ${ID}.bam -@ 48
' sh {} \;
除了生物信息和使用的工具都有效之外,它似乎只执行了第一个命令行 — chromap -i -r $1 -o $1.index
。然后,出于某种原因,一旦进入第二组指令,脚本就会返回以下内容:
找不到序列文件 /hi-c/_1.fq.gz
这表明它不知道我迄今为止成功使用的环境变量,或者它当时无法计算两个以上的操作?我没有任何线索……我还尝试了一些更简单的东西,例如
mkdir $d/scaffolding
find $d/*.fasta -size +100M -exec sh -c '
chromap -i -r $1 -o $1.index && mv $1 $1.index $d/scaffolding
' sh {} \;
但 Bash 抱怨:mv: the destination '/scaffolding' is not a directory
。
我应该怎么做才能让其中一个(或两个)工作?我是否遗漏了什么,如果有人对这个问题有一些见解,请告诉我!提前致谢。
解决几个问题:
$d
,否则$ID
启动sh
者find
将无法看到它们-H
,对于那些fasta
符号链接的文件,find
将检查符号链接的大小,而不是 fasta 文件的大小-prune
,对于那些目录,find
将深入其中。您可能希望使用 将它们全部排除,! -type d
或者仅使用 包含常规文件-type f
(包括指向 的常规文件的符号链接-H
)。添加这些检查并不能消除对 的需求-prune
(-maxdepth 0
如果使用 GNUfind
或兼容)。pipefail
以便如果任何命令失败,管道将返回失败。这现在是一个标准sh
选项,但有些sh
实现dash
仍然不支持它,所以我用 替换了,sh
尽管bash
您可以使用任何其他sh
支持的实现pipefail
。s/\/.//
引号外,这意味着它与 相同,s//.//
这不是有效sed
代码。这里我们使用双引号作为内引号,并将 切换/
为:
分隔符以避免必须转义/
。请注意 会s:/.::
删除 的第一个匹配项,/
后跟任何单个字符且没有任何内容。从/.
字面上删除,即s:/\.::
和s:/\.::g
删除所有匹配项。-exec sh ... {} ';'
,您将为sh
每个文件运行一个,并且不会报告任何失败。 用 替换-exec sh ... {} +
可解决两者的问题。如果您可以切换到 zsh,那么大多数问题就可以轻松避免。
find
功能内置函数,因此您不必将 shell globs (您的*.fasta
)与相结合find
。pipefail
(与某些实现相反sh
)。您假设内联脚本中的几个 shell 变量
sh -c
是通过环境继承的。它们是d
和ID
。如果 shell在find
调用 之前没有将它们导出到环境中,则sh -c
脚本将看不到它们,并将用空字符串代替它们。因此,在拨打电话之前
find
,请确保您已...在你的脚本中。
find
或者,在调用命令时设置它们,如下所示:还要记得对脚本中的所有变量扩展加上双引号: