Bash unixshell能否以某种方式用于报告完成状态?

Bash unixshell能否以某种方式用于报告完成状态?,bash,shell,scripting,ksh,Bash,Shell,Scripting,Ksh,我看到了一些关于SO和外部特定命令(如cat)进度条的想法。然而,我的问题似乎有点偏离标准 目前,我正在shell中使用find命令的功能,例如以下示例: find . -name file -exec cmd "{}" \; 其中“cmd”通常是一种压缩功能或删除工具,用于释放磁盘空间。 当“.”非常大时,这可能需要几分钟,我希望能够报告“状态” 在完成之前,是否有某种类型的进度条、完成百分比,甚至打印周期(即工作…)的方法?如果可能的话,我希望通过添加另一个find来避免增加此执行的持续时

我看到了一些关于SO和外部特定命令(如cat)进度条的想法。然而,我的问题似乎有点偏离标准

目前,我正在shell中使用
find
命令的功能,例如以下示例:

find . -name file -exec cmd "{}" \;
其中“cmd”通常是一种压缩功能或删除工具,用于释放磁盘空间。 当“.”非常大时,这可能需要几分钟,我希望能够报告“状态”

在完成之前,是否有某种类型的进度条、完成百分比,甚至打印周期(即工作…)的方法?如果可能的话,我希望通过添加另一个
find
来避免增加此执行的持续时间。可能吗


提前感谢。

很明显,如果您知道命令运行需要多长时间,或者如果它可以告诉您它已经完成了y中的x个任务,那么您只能拥有进度表或完成百分比

以下是一种简单的方法,可以在某些设备工作时显示指示器:

#!/bin/sh
echo "launching: $@"
spinner() {
    while true; do
        for char in \| / - \\; do
            printf "\r%s" "$char"
            sleep 1
        done
    done
}
# start the spinner
spinner &
spinner_pid=$!
# launch the command
"$@"
# shut off the spinner
kill $spinner_pid
echo ""
因此,您可以这样做(假设脚本名为“progress\u indicator”)


显然,如果您知道该命令将运行多长时间,或者如果它可以告诉您它已经完成了y中的x个任务,那么您只能拥有进度表或完成百分比

以下是一种简单的方法,可以在某些设备工作时显示指示器:

#!/bin/sh
echo "launching: $@"
spinner() {
    while true; do
        for char in \| / - \\; do
            printf "\r%s" "$char"
            sleep 1
        done
    done
}
# start the spinner
spinner &
spinner_pid=$!
# launch the command
"$@"
# shut off the spinner
kill $spinner_pid
echo ""
因此,您可以这样做(假设脚本名为“progress\u indicator”)


如果您安装了
对话框
实用程序(),您可以轻松制作一个漂亮的滚动显示:

find . -type f -name glob -exec echo {} \; -exec cmd {} \; |
dialog --progressbox "Files being processed..." 12 $((COLUMNS*3/2))
--progressbox
的参数是框的标题(可选,不能看起来像数字);文本行的高度和文本列的宽度<代码>对话框有一系列自定义演示文稿的选项;以上只是让你开始

对话框
还有一个进度条,也称为“量表”,但正如@glennjackman在他的回答中指出的那样,你需要知道要显示进度需要做多少工作。一种方法是收集find命令的整个输出,计算其中的文件数,然后从累积的输出中运行所需的任务。但是,这意味着要等到find命令完成后才能开始工作,这可能是不可取的

就因为这是一个有趣的挑战,我提出了以下解决方案,这可能是过度设计的,因为它试图解决我能想到的所有shell问题(即使如此,它也可能遗漏了一些)。它由两个shell文件组成:

# File: run.sh

#!/bin/bash
# Usage: run.sh root-directory find-tests
#
# Fix the following path as required
PROCESS="$HOME/bin/process.sh"
TD=$(mktemp --tmpdir -d gauge.XXXXXXXX)
find "$@" -print0 |
tee >(awk -vRS='\0' 'END{print NR > "'"$TD/_total"'"}';
      ln -s "$TD/_total" "$TD/total") |
{ xargs -0 -n50 "$PROCESS" "$TD"; printf "XXX\n100\nDone\nXXX\n"; } |
dialog --gauge "Starting..." 7 70 
rm -fR "$TD"

# File: process.sh

#!/bin/bash
TD="$1"; shift
TOTAL= 
if [[ -f $TD/count ]]; then COUNT=$(cat "$TD/count"); else COUNT=0; fi
for file in "$@"; do
  if [[ -z $TOTAL && -f $TD/total ]]; then TOTAL=$(cat "$TD/total"); fi
  printf "XXX\n%d\nProcessing file\n%q\nXXX\n" \
         $((COUNT*100/${TOTAL:-100})) "$file"
  #
  # do whatever you want to do with $file
  #
  ((++COUNT))
done
echo $COUNT > "$TD/count"
一些注意事项:

上面有很多分散的gnu扩展。我还没有列出一个完整的列表,但它肯定包括
%q
printf格式(可能只是
%s
);用于NUL终止文件名列表的标志,以及
--tmpdir
标志到
mktemp

run.sh
使用
tee
同时计算找到的文件数(使用
awk
)并开始处理文件

xargs
-n50
参数使其仅等待前50个文件,以避免在find花费大量时间未找到第一个文件时延迟启动;这可能没有必要

awk
-vRS='\0'
参数使其使用
NUL
作为行分隔符,以将
-print0
操作与
查找
(以及
-0
选项与
xargs
匹配);仅当文件路径可能包含新行时,才需要执行所有这些操作

awk
将计数写入
\u total
,然后我们将
\u total
符号链接到
total
,以避免在完全写入之前读取
total
的非常不可能的竞争条件。符号链接是原子的,因此这样做可以保证
total
不存在或完全写入

计算文件的总大小可能比只计算它们要好,特别是当处理工作与文件大小(例如压缩)相关时。这将是一个相当简单的修改。此外,使用
xargs
并行执行特性也很有诱惑力,但这需要更多的工作来协调并行进程之间已处理文件的总和


如果您使用的托管环境没有
对话框
,最简单的解决方案就是从有
对话框
的环境中使用
ssh
运行上述脚本。从run.sh中删除
| dialog--gauge“Starting…”7 70
,并将其放在
ssh
调用中:
sshuser@host/path/to/run.sh root dir find tests | dialog--gauge“Starting…”7 70

如果安装了
dialog
实用程序(),您可以轻松制作一个漂亮的滚动显示:

find . -type f -name glob -exec echo {} \; -exec cmd {} \; |
dialog --progressbox "Files being processed..." 12 $((COLUMNS*3/2))
--progressbox
的参数是框的标题(可选,不能看起来像数字);文本行的高度和文本列的宽度<代码>对话框有一系列自定义演示文稿的选项;以上只是让你开始

对话框
还有一个进度条,也称为“量表”,但正如@glennjackman在他的回答中指出的那样,你需要知道要显示进度需要做多少工作。一种方法是收集find命令的整个输出,计算其中的文件数,然后从累积的输出中运行所需的任务。但是,这意味着要等到find命令完成后才能开始工作,这可能是不可取的

仅仅因为这是一个有趣的挑战,我就提出了以下解决方案,这可能是过度设计的,因为它试图解决我能想到的所有shell问题(甚至