要顺序执行多条命令,但希望每次执行之前都做些额外的辅助操作:
- 将执行历史写进一个 txt 文件,用来查进度;
- 每次执行之前,用 [1] 重新找一次 GPU 列表(因为多人用,要动态刷新顺序);
- 如果某命令执行失败,写入另一个 txt 文件,用来定位 bug。
示例如下:
#!/bin/bash
run()
{
# 记录执行历史
echo $(date) >> RUNNING.txt
eval echo $1 >> RUNNING.txt
# 重寻 GPU 列表
. find_gpu.sh -1 8000
# 执行传入的命令
# 此处用 `eval` 延迟解析/替换 `$1` 中的「形参」`${gpu_id}`
eval $1
if [ $? -ne 0 ]; then
# 若出错,记录出错命令
echo $(date) > FAILED.txt
eval echo $1 >> FAILED.txt
# 并中止
exit
fi
}
# 删旧报错、执行历史
if [ -e FAILED.txt ]; then rm FAILED.txt; fi
if [ -e RUNNING.txt ]; then rm RUNNING.txt; fi
# 顺序执行多条命令
# 其中 `-g ${gpu_id}` 指定使用的 GPU(列表)
# 注意,用单引号「'」,而不是双引号「"」
# 因为用双引号的话,`${gpu_id}` 会被**立即**替换
# 而我希望它在 `run` 中重寻 GPU 列表之后再替换(即延时替换)
# 我将此处未被替换的 `${gpu_id}` 称为「形参」
run 'python program1.py -g ${gpu_id}'
run 'python program2.py -g ${gpu_id}'
run 'python program3.py -g ${gpu_id}'
其中,run
后面的参数是要执行的命令,而 run
函数中加了一些辅助命令(详见注释)。此处主要指出单引号「'
」和 eval
命令的配合使用:
run
的参数用单引号「'
」括住,于是里面的${gpu_id}
不会立即被替换(如果用双引号「"
」就会被立即替换)。我将这个未被替换的${gpu_id}
称为形参;run
内先用. find_gpu.sh
重寻 GPU 列表,此命令会对变量gpu_id
赋值(详见 [1]);- 然后,再用
eval
替换$1
中的形参${gpu_id}
并执行,即其替换时机被延迟了。