如何重新运行跳过以前运行过的行的bash脚本?

时间:2015-12-22 10:45:19

标签: linux bash

我有一个bash脚本,它充当分析管道的包装器。如果脚本出错,我希望能够通过重新运行原始命令从发生错误的位置运行脚本。我设置了两个不同的陷阱;一个将删除在我的脚本非零退出时生成的最后一个文件,另一个将删除退出信号= 0上的所有临时文件,并在运行结束时基本上清理文件系统。我在bash环境中启用了noclobber,它允许我的脚本跳过已经写入文件的脚本行但是如果我没有设置非零退出陷阱,这只会执行此操作。一旦我设置了这个陷阱,它就会在第一行退出,其中noclobber为不会覆盖的文件ID。有没有办法让我跳过以前成功运行的代码行,而不是从一开始就重新运行我的代码?我知道我可以为每一行使用条件语句,但我认为可能有一种更简洁的方法来做到这一点。

set -o noclobber

# Function to clean up temporary folders when script exits at the end
rmfile() { rm -r $1 }

# Function to remove the file being currently generated
# Function executed if script errors out

rmlast() {
if [ ! -z "$CURRENTFILE" ]
then
rm -r $1
exit 1
fi }

# Trap to remove the currently generated file
trap 'rmlast "$CURRENTFILE"' ERR SIGINT

#Make temporary directory if it has not been created in a previous run
TEMPDIR=$(find . -name "tmp*")
if [ -z "$TEMPDIR" ]
then
TEMPDIR=$(mktemp -d /test/tmpXXX)
fi

# Set CURRENTFILE variable
CURRENTFILE="${TEMPDIR}/Variants.vcf"

# Set CURRENTFILE variable
complexanalysis_tool input_file > $CURRENTFILE

# Set CURRENTFILE variable
CURRENTFILE="${TEMPDIR}/Filtered.vcf"

complexanalysis_tool2 input_file2 > $CURRENTFILE

CURRENTFILE="${TEMPDIR}/Filtered_2.vcf"

complexanalysis_tool3 input_file3 > $CURRENTFILE

# Move files to final destination folder
mv -nv $TEMPDIR/*.vcf /test/newdest/

# Trap to remove temporary folders when script finishes running
trap 'rmfile "$TEMPDIR"' 0

更新

我收到了建议使用make实用程序的答案。我想利用其内置实用程序来检查是否已满足依赖项。 在我手中,VK Kashyap建议的makefile似乎没有跳过以前完成的任务的执行。因此,例如,我运行上面的脚本并在使用ctrl c运行filtered.vcf时中断脚本。当我再次重新运行脚本时,它再次从头开始运行,即再次从varaints.vcf开始。我是否遗漏了一些东西,以便让makefile显示来源已满了?

回答更新:

好的,这是一个新手的错误,但由于我不熟悉生成makefile,我会发布我的错误的解释。我的makefile没有从退出点重新运行的原因是我将目标命名为正在生成的输出文件的不同名称。因此,如果您为目标命名,VK Kashyap会正确回答,例如。

variants.vcf
filtered.vcf
filtered2.vcf

与生成的输出文件相同,然后脚本将跳过以前完成的任务。

2 个答案:

答案 0 :(得分:3)

make实用程序可能是你想要实现的东西的答案。

它有内置的依赖性检查(你试图用tmp文件实现的东西)

#run all target when all of the files are available
all: variants.vcf filtered.vcf filtered2.vcf
   mv -nv $(TEMPDIR)/*.vcf /test/newdest/

variants.vcf:
    complexanalysis_tool input_file > variants.vcf

filtered.vcf:
    complexanalysis_tool2 input_file2 > filtered.vcf

filtered2.vcf:
    complexanalysis_tool3 input_file3 > filtered2.vcf

您可以使用bash脚本将此make文件调用为:

#/bin/bash

export TEMPDIR=xyz
make -C $TEMPDIR all

make实用程序将检查已完成的任务并跳过执行完成的任务。它会在你完成任务的错误的地方继续。

您可以在互联网上找到有关makefile的确切语法的更多详细信息。

答案 1 :(得分:2)

没有内置的方法来做到这一点。

但是,可以通过跟踪上一个成功的行并构建您自己的goto语句来这样做,如here和{{3}所述(只需将'标签'替换为实际的行号)。

然而,问题是这是否真的是智能的想法。

更好的方法是只运行所需的命令,而不是尚未执行的命令。 这可以通过bash-script中的显式条件来完成:

produce_if_missing() {
   # check if first argument is existing
   # if not run the rest of the arguments and pipe it into the first one
   local curfile=$1
   shift
   if [ ! -e "${curfile}" ]; then
     $@ > "${curfile}"
   fi
}

produce_if_missing Variants.vcf complexanalysis_tool input_file
produce_if_missing Filtered.vcf complexanalysis_tool2 input_file2

或使用为此类事物制作的工具(请参阅VK Kahyap使用make的答案,但我更喜欢在制作规则中使用变量以最大限度地减少拼写错误):

Variants.vcf: input_file
    complexanalysis_tool $^ > $@
Filtered.vcf: input_file
    complexanalysis_tool2 $^ > $@