【问题标题】:Customized progress message for tasks in bash scriptbash 脚本中任务的自定义进度消息
【发布时间】:2013-02-09 14:38:54
【问题描述】:

我目前正在编写一个 bash 脚本来自动执行任务。在我的脚本中,我希望它在执行任务时显示进度消息。

例如:

user@ubuntu:~$ 配置一些东西

->

配置一些东西。

->

配置一些东西..

->

配置一些东西...

->

配置一些东西......完成

所有进度消息都应该出现在同一行。 以下是我目前的解决方法:

echo -n "Configure something "
exec "configure something 2>&1 /dev/null"
//pseudo code for progress message
echo -n "." and sleep 1 if the previous exec of configure something not done
echo " done" if exec of the command finished successfully
echo " failed" otherwise

exec 会等待命令完成,然后再继续执行脚本行吗? 如果是这样,那么我如何在执行配置某事的同时回显消息? 我如何知道 exec 何时完成上一个命令并返回 true?使用$? ?

【问题讨论】:

    标签: bash


    【解决方案1】:

    只是为了戴上编辑的帽子,如果出现问题怎么办?您或您脚本的用户如何知道什么出了问题?这可能不是您要寻找的答案,但是让您的脚本单独执行每个构建步骤可能会总体上更好,尤其是对于故障排除。为什么不定义一个函数来验证您的构建步骤:

    function validateCmd()
    {
      CODE=$1
      COMMAND=$2
      MODULE=$3
    
      if [ ${CODE} -ne 0 ]; then
        echo "ERROR Executing Command: \"${COMMAND}\" in Module: ${MODULE}"
        echo "Exiting."
        exit 1;
      fi
    }    
    
    ./configure
    validateCmd $? "./configure" "Configuration of something"
    

    无论如何,是的,正如您在上面可能注意到的那样,使用$? 来确定最后一个命令的结果是什么。例如:

    rm -rf ${TMP_DIR}
    
    if [ $? -ne 0 ]; then
      echo "ERROR Removing directory: ${TMP_DIR}"
      exit 1;
    fi
    

    要回答您的第一个问题,您可以使用:

    echo -ne "\b"
    

    删除同一行的一个字符。因此,要在一行中数到十,您可以执行以下操作:

    for i in $(seq -w 1 10); do
      echo -en "\b\b${i}"
      sleep .25
    done
    echo
    

    这样做的诀窍是您必须知道要删除多少,但我相信您可以弄清楚。

    【讨论】:

    • 谢谢。你是对的,我不应该将所有的 stdout 和 stderr 都指向 null,而是指向某个日志文件。
    • cmd; if [ $? -ne 0 ]; then foo 写得更好,更惯用if ! cmd; then foo
    【解决方案2】:

    你不能这样打电话给exec; exec 永远不会返回,并且 exec 之后的行将不会执行。在一行上打印进度更新的标准方法是在每行的末尾简单地使用\r 而不是\n。例如:

    #!/bin/bash
    
    i=0
    sleep 5 &   # Start some command
    pid=$!      # Save the pid of the command
    while sleep 1; do    # Produce progress reports
        printf '\rcontinuing in %d seconds...' $(( 5 - ++i ))
        test $i -eq 5 && break
    done
    if wait $pid; then echo done; else echo failed; fi
    

    这是另一个例子:

    #!/bin/bash
    
    execute() {
        eval "$@" &  # Execute the command
        pid=$!
    
        # Invoke a shell to print status.  If you just invoke
        # the while loop directly, killing it will generate a
        # notification.  By trapping SIGTERM, we suppress the notice.
        sh -c 'trap exit SIGTERM
        while printf "\r%3d:%s..." $((++i)) "$*"; do sleep 1
        done' 0 "$@" &
        last_report=$!
        if wait $pid; then echo done; else echo failed; fi
        kill $last_report
    }
    execute sleep 3
    execute sleep 2 \| false   # Execute a command that will fail
    execute sleep 1
    

    【讨论】:

    • 这个方法比我以前用过的方法优越。谢谢!
    猜你喜欢
    • 1970-01-01
    • 2022-09-26
    • 1970-01-01
    • 1970-01-01
    • 2013-05-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-30
    相关资源
    最近更新 更多