2010-03-11 77 views
1

除了我之前关于shell脚本中多线程的查询 我很好奇它是否可能有多个进度条。多进度条

这里是我的预期结果的代码片段:

Output : 1 of 100 Files Completed # Thread1 
Output : 10 of 45 files Completed  # Thread 2  

该行更新显示进度。它有可能实现它的外壳。 希望你的帮助,如果任何人有这个想法。

问候 基兰

回答

1

像什么pv -c呢?

当然,请参阅src/pv/cursor.c。虽然从shell只能安全地执行,但一个小型的C工具可以处理它。

+0

是否有可能与shell中的printf语句不同的转义字符\ n \ r等? – Kiran 2010-03-11 23:59:42

+0

不是。你如何防止两个线程同时写入终端并搞乱线路?你必须使用ANSI转义来设置光标位置*向上*一行。 – ephemient 2010-03-12 00:20:41

+0

雅ephemient,这就是我正在看。如果这是可能的使用shell脚本..我知道,我期待太多..会很好,如果我能做到这一点.. – Kiran 2010-03-12 09:36:29

1

是的,这是非常有可能的。

假设现有的代码(根据您以前的帖子),目前是这样的:

do_something() { 
    ... 
    echo -ne "\r$index of $No_of_Files Completed" 
    ... 
} 

do_something A & 
do_something B & 
do_something C & 
wait 

...那么你可以为了达到你心目中的效果进行以下调整:

# Background tasks will no longer write directly to the console; instead, 
# they will write to temporary files which will be read periodically 
# by a special log printer task (which will display everything nicely.) 
# 
# Name of temporary files 
STATUS_BASENAME="/tmp/~$$.status" 
# Process IDs of backgrounded tasks; we record them so we can wait on them 
# specifically but not wait on the special log printer task 
TASK_PIDS="" 

do_something() { 
    # First parameter must be a task ID starting at 0 incremented by 1 
    TASK_ID=$1 ; shift 
    ... 
    # We write new status to status file (note we don't echo -n, we want that 
    # trailing newline) 
    # Try to go through a temporary status file which we rename afterwards to 
    # avoid race conditions with the special log printer task 
    echo "$x of 5 Completed" >"${STATUS_BASENAME}.${TASK_ID}.tmp" 
    mv "${STATUS_BASENAME}.${TASK_ID}.tmp" "${STATUS_BASENAME}.${TASK_ID}" 
    ... 
} 

# Special log printer task 
status_printer() { 
    # First time in the loop is special insofar we don't have to 
    # scroll up to overwrite previous output. 
    FIRST_TIME=1 
    while true ; do 
    # If not first time, scroll up as many lines as we have 
    # regular background tasks to overwrite previous output. 
    test $FIRST_TIME -eq 0 && for PID in $TASK_PIDS ; do 
     echo -ne '\033M' # scrol up one line using ANSI/VT100 cursor control sequences 
    done 
    FIRST_TIME=0 
    TASK_ID=0 
    for PID in $TASK_PIDS ; do 
     # If status file exists print first line 
     test -f "${STATUS_BASENAME}.${TASK_ID}" && head -1 "${STATUS_BASENAME}.${TASK_ID}" || echo "waiting..." 
     TASK_ID=`expr $TASK_ID + 1` # using expr for portability :) 
    done 
    test -f "${STATUS_BASENAME}.done" && return 
    sleep 1 # seconds to wait between updates 
    done 
} 

do_something 0 A & 
TASK_PIDS="$TASK_PIDS $!" 
do_something 1 B & 
TASK_PIDS="$TASK_PIDS $!" 
do_something 2 C & 
TASK_PIDS="$TASK_PIDS $!" 

status_printer & 
    PRINTER_PID=$! 

# Wait for background tasks 
wait $TASK_PIDS 

# Stop special printer task instead of doing just 
# kill $PRINTER_PID >/dev/null 
touch "${STATUS_BASENAME}.done" 
wait $PRINTER_PID 

# Cleanup 
rm -f "${STATUS_BASENAME}."* 
+0

非常感谢您花时间在开发此代码.. 我会试试这个如果它符合我的框架。我在考虑是否有一些使用echo和printf语句组合的明显方式。感谢你的帮助 – Kiran 2010-03-12 09:10:03

0

如果你的子进程输出过滤,那么你可以在每个subproc的标准输出重定向到一个不同的文件描述符,然后调用通过文件描述符的输出功能循环。然后你可以尝试使用printf来更新进度表。这是你会遇到麻烦的地方。不确定Bash的内置printf可以处理终端的细节。我从来没有试图在Bash中编写一个多线程输出的进度表。为什么不使用对话框?