如何在Bash脚本中实现Ete-Toolkit软件的标准输出实时刷新至日志文件
我完全懂你现在的糟心处境——跑一周的任务输出不实时刷进日志,没法及时看错误,还天天担心断电断网要从头再来。下面给你几个针对性的解决方案,一步步来:
一、搞定实时输出刷新问题
你之前对stdbuf的用法有点误区,它完全能在Bash脚本里用,关键是要直接套在目标命令上,不是单独执行。试试这几个办法:
1. 用stdbuf配置行缓冲
修改脚本里的ete3执行命令,把stdbuf作为前缀直接作用在命令上:
stdbuf -oL ete3 build -w mafft_default-none-none-none -m sptree_fasttree_all -o provaflush --cogs coglist_species_filtered.txt -a multifasta_speciesunique.fa --clearall --cpu 40
注意:你的脚本已经通过SGE的
#$ -o和#$ -e把stdout/stderr重定向到logs_40markers了,不需要再加&>> logs_40markers,重复重定向反而可能出问题。
-oL参数会让stdout用行缓冲模式,每输出一行就立刻写入日志,不会攒够缓冲区才刷新。
2. 用Python环境变量直接禁用缓冲
如果stdbuf还是没效果,直接给Python设置PYTHONUNBUFFERED环境变量——毕竟Ete-Toolkit是Python写的,这个方法更直接:
PYTHONUNBUFFERED=1 ete3 build -w mafft_default-none-none-none -m sptree_fasttree_all -o provaflush --cogs coglist_species_filtered.txt -a multifasta_speciesunique.fa --clearall --cpu 40
这个变量会强制Python关闭stdout的缓冲,输出会实时刷到日志里。
3. 用unbuffer模拟终端交互
如果集群装了expect工具包(大部分生物信息集群都有),可以用unbuffer命令:
unbuffer ete3 build -w mafft_default-none-none-none -m sptree_fasttree_all -o provaflush --cogs coglist_species_filtered.txt -a multifasta_speciesunique.fa --clearall --cpu 40
它会模拟终端环境,让程序以为在和人交互,自动关闭缓冲,效果很稳。
二、解决任务中断后的重启难题
既然任务要跑一周,断电断网风险高,光解决日志还不够,得保证能从断点续跑:
1. 检查Ete-Toolkit的断点续传功能
先查下ete3 build的帮助文档:
ete3 build --help
很多生物信息工具都自带断点续传参数(比如--resume或--continue),如果ete3支持,下次重启任务时加上这个参数,就能从上次中断的地方接着跑,不用从头再来。
2. 定时备份中间文件
在脚本里加个后台定时备份的逻辑,比如每小时备份一次输出目录provaflush:
# 启动后台备份任务,每小时同步一次中间结果 while true; do rsync -av --delete provaflush/ provaflush_backup/ sleep 3600 done & # 记录备份进程PID,任务结束后杀掉它 BACKUP_PID=$! # 执行ete3命令(选上面任意一种刷新方案) PYTHONUNBUFFERED=1 ete3 build ... # 任务完成后终止备份进程 kill $BACKUP_PID
这样就算断电,备份的中间文件也能帮你快速恢复进度。
3. 利用SGE集群的自动重启机制
你的脚本用了SGE提交指令,可以加一行让集群自动重启失败的任务:
#$ -r y
这样如果任务因为节点断电、网络波动中断,SGE会自动帮你重新提交任务,配合断点续传参数,几乎不用手动干预。
总结
优先试PYTHONUNBUFFERED=1或者stdbuf -oL解决实时日志问题,同时结合断点续传和中间文件备份应对中断。这样既能实时监控任务状态,又不用再担心断电要从头跑一周了。
内容的提问来源于stack exchange,提问作者MagíBC

