我有一个脚本,我想每 x 秒运行一次,直到输出发生变化。通过一个简单的 while 或 until 循环,我知道如何使用 grep 检查特定字符串的输出,但我想要做的是继续迭代循环,直到当前迭代的输出不等于前一次迭代的输出。
我怎样才能在 bash 中实现这一点?
我得到的最接近的是下面,命令在每次迭代中运行两次,但这会产生额外的运行,因为 while 循环无法记住上一次迭代的输出。
while [ "$(command)" = "$(command)" ]; do sleep 10m; done
Run Code Online (Sandbox Code Playgroud)
Kam*_*ski 56
来自man 1 watch
:
-g
,--chgexit
当命令的输出改变时退出。
watch
POSIX 不需要,但无论如何它很常见。在 Debian 或 Ubuntu 中,它procps
与kill
和ps
(以及一些其他工具)一起包含在包中。
例子:
watch -g -n 5 'date +%H:%M'
Run Code Online (Sandbox Code Playgroud)
这应该可以解决问题 - 内联解释:
#!/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
Run Code Online (Sandbox Code Playgroud)
可能有更简单的方法可以做到这一点,但它有几个有用的功能:
mktemp
用于每个输出。diff
命令看到两个相同的文件。这避免了重复我们正在测试的命令,代价是额外diff
执行一次。显然,这watch
是去这里的方法,如另一个答案中所述。但是,如果您确实想要或需要在 shell 中执行此操作,可以使用以下一种方法:
#!/bin/sh
unset prev
while output=$(some_command);
[ "${prev+set}" != set ] || [ "$output" = "$prev" ];
do
prev=$output
sleep 10;
done
Run Code Online (Sandbox Code Playgroud)
"${prev+set}"
扩展为set
ifprev
在开始时未设置后设置为一个值,因此实际上它强制循环的内容至少运行一次。或者,我们可以prev
以prev=$(some_command)
在some_command
循环开始时运行额外时间为代价进行初始化。
此外,如评论中所述,命令替换会从命令输出中删除所有尾随换行符,因此如果结果中的唯一更改是这些更改,则将无法区分输出。不过,这应该很少重要。