如何在并行LTO磁带迁移脚本中记录每个任务的起止时间?
问题描述
正在执行LTO-6到LTO-9的磁带迁移,使用GNU Parallel的sem命令实现2/4台磁带驱动器并行工作。脚本功能正常,但日志记录不符合预期:需要记录每个磁带迁移任务的启动和完成时间,但当前要么只能在循环结束后记录整个批次的完成时间,要么错误地把启动时间当成了结束时间(因为sem后台运行,脚本没等任务完成就写了结束日志)。
期望的日志格式:
>>> STARTED 000123 at 2025-06-14_07:43 !!! FINISHED 000123 at 2025-06-14_12:20 >>> STARTED 000437 at 2025-06-14_07:43 !!! FINISHED 000437 at 2025-06-14_13:05
或
>>> STARTED 000123 at 2025-06-14_07:43 >>> STARTED 000437 at 2025-06-14_07:43 !!! FINISHED 000123 at 2025-06-14_12:20 !!! FINISHED 000437 at 2025-06-14_13:05
当前使用的脚本片段:
function process1() { VAR1=( $(cat ${LIST1}) ) if [[ ${VAR1[@]} ]]; then for i in "${VAR1[@]}"; do DATE=$(date +%Y-%m-%d_%R) echo ">>> STARTED" ${i} at $DATE >> /scratch/Migrate/job1.daily.progress # 磁带转换命令 sem -j${JOB} --id my_id1 fsmedcopy -T ANTF -s LTO6_Pool_a -v LTO9_Pool_4 -G y -r ${i} echo -e "Active tape ${i}" done sem --wait --id my_id1 DATE=$(date +%Y-%m-%d_%R) echo "!!! FINISHED JOB" ${LIST1} at $DATE >> /scratch/Migrate/job1.daily.progress echo "" >> /scratch/Migrate/job1.daily.progress fi exit }
实际得到的错误日志:
>>> STARTED 000123 at 2025-06-14_07:43 >>> STARTED 000437 at 2025-06-14_07:43 !!! FINISHED 000123 at 2025-06-14_07:43 !!! FINISHED 000437 at 2025-06-14_07:43
核心问题:sem后台启动任务,原脚本的结束日志要么是批量写整个批次的时间,要么会立刻执行导致时间与启动时间一致。需要在保留并行的前提下,为每个任务单独记录真实的启动和完成时间。
解决方案
把单条磁带的迁移逻辑(含日志记录)封装成独立函数,让sem直接调用这个函数,这样每个任务的启动/结束日志会在任务实际执行的上下文里生成,时间完全准确。
修改后的脚本:
# 定义单磁带处理函数,包含日志记录 process_tape() { local tape_id=$1 local log_file="/scratch/Migrate/job1.daily.progress" # 记录启动时间 local start_time=$(date +%Y-%m-%d_%R) echo ">>> STARTED ${tape_id} at ${start_time}" >> "${log_file}" # 执行磁带迁移命令 fsmedcopy -T ANTF -s LTO6_Pool_a -v LTO9_Pool_4 -G y -r "${tape_id}" # 记录完成时间(命令执行完才会走到这一步) local finish_time=$(date +%Y-%m-%d_%R) echo "!!! FINISHED ${tape_id} at ${finish_time}" >> "${log_file}" echo -e "Active tape ${tape_id} completed" } function process1() { # 读取磁带列表,避免原写法的分词问题(比如磁带ID含特殊字符的情况) local VAR1=() while IFS= read -r line; do VAR1+=("$line") done < "${LIST1}" if [[ ${#VAR1[@]} -gt 0 ]]; then # 用sem并行调用处理函数,-j指定并行数 for i in "${VAR1[@]}"; do sem -j${JOB} --id my_id1 process_tape "${i}" done # 等待所有并行任务完成 sem --wait --id my_id1 # 可选:记录整个批次的完成时间 local batch_finish=$(date +%Y-%m-%d_%R) echo "!!! FINISHED BATCH ${LIST1} at ${batch_finish}" >> /scratch/Migrate/job1.daily.progress echo "" >> /scratch/Migrate/job1.daily.progress fi exit }
关键改动说明
- 封装单任务逻辑:把单磁带的日志记录和迁移命令放进
process_tape函数,确保启动日志在迁移命令执行前生成,完成日志在命令执行完成后生成,时间完全对应真实任务周期。 - 修正列表读取方式:用
while read读取磁带列表,避免原cat+数组写法在磁带ID含空格/特殊字符时的分词错误。 - 并行任务调度:
sem直接调用封装后的函数,每个函数实例对应一个独立的磁带迁移任务,并行执行的同时保证日志的准确性。 - 批次日志可选:保留了整个批次的完成日志(如果不需要可以删除),但每个任务的单独日志已经满足需求。
这样修改后,日志会按照任务实际的启动和完成时间生成,完全符合期望的格式。
内容的提问来源于stack exchange,提问作者Robin
相关产品推荐
相关产品推荐

