我有一个脚本,希望每 x 秒运行一次,直到输出发生变化。使用简单的 while 或 Until 循环,我知道如何使用 grep 检查特定字符串的输出,但我想要做的是继续迭代循环,直到当前迭代的输出不等于上一次迭代的输出。
我怎样才能在 bash 中实现这一点?
我得到最接近的结果如下,其中命令在每次迭代中运行两次,但这会产生额外的运行,因为 while 循环无法记住上一次迭代的输出。
while [ "$(command)" = "$(command)" ]; do sleep 10m; done
答案1
-g
,--chgexit
当输出命令变化。
watch
POSIX 并不要求它,但它很常见。在 Debian 或 Ubuntu 中,它procps
与kill
和ps
(以及一些其他工具)一起包含在软件包中。
例子:
watch -g -n 5 'date +%H:%M'
答案2
这应该可以解决问题-内联解释:
#!/usr/bin/env bash
# Exit if any errors occur or any undefined variables are dereferenced
set -o errexit -o nounset
# Store the outputs in a separate directory
output_directory="$(mktemp --directory)"
last_output_file="${output_directory}/last"
current_output_file="${output_directory}/current"
touch "$current_output_file"
ln --symbolic "$current_output_file" "$last_output_file"
# The count is just here to show that we always run at least twice, and that
# after that we run the command a random number of times.
count=0
while true
do
echo "$((++count))"
# This is our command; it prints 0 or 1 randomly
if [[ "$RANDOM" -gt 16383 ]]
then
echo 0 > "$current_output_file"
else
echo 1 > "$current_output_file"
fi
# Abort the loop when the files differ
if ! diff --brief "$last_output_file" "$current_output_file"
then
break
fi
# Shunt the current output to the last
mv "$current_output_file" "$last_output_file"
done
可能有更简单的方法可以做到这一点,但它具有几个有用的功能:
- 它避免创建任何多余的文件,例如用于
mktemp
每个输出的文件。 - 通过以最后一个输出文件作为当前输出文件的符号链接开始,我们保证第一个
diff
命令会看到两个相同的文件。这避免了重复执行我们正在测试的命令,但需要额外diff
执行一次。
答案3
显然,watch
这是要走的路,正如另一个答案。但是如果你确实想要或者需要在 shell 中执行此操作,这里有一种方法可以做到:
#!/bin/sh
unset prev
while output=$(some_command);
[ "${prev+set}" != set ] || [ "$output" = "$prev" ];
do
prev=$output
sleep 10;
done
"${prev+set}"
set
如果prev
在开始时取消设置后设置为某个值,则扩展为,因此实际上它会强制循环的内容至少运行一次。或者,我们可以初始化prev
为,但prev=$(some_command)
代价是some_command
在循环开始时额外运行一次。
此外,正如注释中所述,命令替换会从命令输出中删除所有尾随换行符,因此如果结果中唯一的变化就是这些换行符,则无法区分输出。不过,这应该很少会造成影响。