bash脚本中任务的自定义进度消息

时间:2013-02-09 04:25:35

标签: bash

我正在编写一个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?使用$?

2 个答案:

答案 0 :(得分: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

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

答案 1 :(得分:1)

你不能那样打电话给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