gnu parallel:在sigint上打印部分输出



我使用gnu parallel为开发中的程序运行测试输入。简化设置:

find . -iname '*test*' | parallel -k -I@ echo running '@' ; my_binary ; echo '@': exited with $?

如果my_binary陷入无限循环,我Ctrl+C ->SigINT这个测试脚本

这里,不幸的是,parallel吃掉了所有的(已经打印,但是为排序缓冲)标准输出,所以我不能看到哪个测试卡住了。

我想要得到这个标准输出,但是我在手册页中没有找到这样做的选项。你有什么好主意吗?

  • 我想保持输出的顺序(这里是由-k引起的),所以只是将所有输出直接重定向到一个文件是行不通的(除非有一个我不知道的技巧?)

  • 为每个测试设置某种超时是不切实际的

    (有些测试需要很长时间,但你知道有一个问题很漂亮。(由于CPU使用等原因)。

  • 我真的不关心使用gnu-parallel,任何解决方案都会很棒。

询问GNU Parallel当前正在运行哪些作业:

seq 1000 | parallel sleep &
pid=$!
sleep 10
kill -SIGUSR1 $pid

好吧,我自己弄明白了。

parallel有一个--joblog选项,立即打印所有完成的工作,但只在提交的顺序!

这正是我们想要的,结合@Mark Setchell的标签想法对于以下概念证明:


output="$(mktemp)" # parallel will put the line buffered command output here
joblog="$(mktemp)" # parallel will output it's joblog here for sigint recovery
function run_test () {
tag="$1"
input="$2"
echo "$tag: started $input"
# simulate doing work for demonstration
sleep "$tag"
# output from the test must have the tag prepended to each line 
echo "$input: test output"  2>&1 | sed "s/^/$tag: /" 
echo "$tag: finished $input, exited with $?"
}
function handle_sigint () {
echo " interrupted!"
# check for finished jobs (tag in the joblog)
awk '(NR>1){printf "^%s: n", $1}' "$joblog"  | 
# remove all output lines with tags from finished jobs
grep -v -f - "$output" | 
# print the remaining output lines, sorted by tag, but in order of line submission
sort -snk1 |
# but strip away the tag from the beginning of the line
cut -d" " -f2-
rm "$output"
rm "$joblog"
exit 0
}
export -f run_test
trap handle_sigint INT
# create some dummy jobs for demonstration
printf "foonbarnbaznquuxn" | 
# create command to run for each test
awk '{printf "run_test %i %sn", NR, $1}' | 
# run the jobs, putting line buffered output into $output and the joblog into $joblog
parallel --line-buffered --joblog "$joblog" bash -c  &>"$output" & 
# immedeately pipe new joblog lines along until parallel dies or we sigint
tail -f "$joblog" --pid $! |
# whenever a job is finished --> a joblog line is added, print all lines with that tag from the output
awk "(NR>1){c=sprintf("sed -n 's/^%s: //p' '%s'\n" , $1, "$output"); system(c)}" 
# remove the temp files (if we were not interrupted, otherwise handle_sigint does this)
rm "$output" 
rm "$joblog"

最新更新