for
我在交互式会话中开始循环bash
。对于这个问题,我们可以假设循环是这样的
for i in dir/*; do
program "$i"
done > log
该命令花费的时间比预期长得多,但仍然运行。如何查看当前运行for
循环的进度。
非解决方案:
- 看着
log
。
不起作用,因为:program
预计会安静地运行。您可以将其视为program
验证者。如果循环完成而没有任何输出,那么我很高兴。 - 停止循环。添加某种进度指示(例如
echo "$i"
)。再次开始循环。
不起作用,因为:该循环已经运行了几个小时。我不想浪费当前投入的所有时间和精力。我认为一切正常。我只是好奇,想知道目前的进展。 - Ctrl+Z然后
set -x; fg
不起作用,因为:bash
使用时不继续循环fg
。只有循环内的当前/下一个命令运行后fg
,循环才会退出。您可以使用 自己尝试一下for i in {1..200}; do printf '%s ' $i; /usr/bin/sleep 0.5; done
。
答案1
通配符dir/*
始终以相同的顺序扩展。此功能与当前值一起$i
可用于显示进度信息。
$i
可以通过查看系统上运行的进程来检索 的当前值。这以下命令打印当前运行的实例program
及其参数。
如果有多个program
进程,您可能需要使用--parent ...
选项来仅匹配由运行要检查的循环
pgrep
的 shell 启动的进程。for
ps -o args= -fp $(pgrep program)
手动提取 的值$i
,然后使用获取进度
a=(dir/*)
n=$(printf %s\\0 "${a[@]}" | grep -zFxnm1 'the exact value of $i' | cut -f1 -d:)
echo "Progress: $n / ${#a[@]}"
这在两个假设下有效
dir/
运行循环时的内容不会改变。如果program
创建、重命名或删除文件,则数字可能是错误的。调用
program
开始一个新的进程。如果program
是一个bash
函数,则 不会有子流程program
。如果函数function
本身调用另一个启动新进程的程序,那么您可以查找该子程序。但是,如果program
是 bash 内置函数(由 列出的命令help
)或纯 bash 函数(仅使用bash
内置函数),那么您就不走运了。
如果您遇到问题 2 或者您的for
循环具有与问题中的结构不同的结构(例如,program < "$1"
或者具有许多不同程序的非常长的循环体),那么您可能可以lsof
通过查看由您当前的 shell 会话或其子进程。