【问题标题】:Execute command once per true condition(s) & wait until condition(s) returns false then true again每个条件为真时执行一次命令并等到条件返回假然后再次为真
【发布时间】:2014-11-24 11:11:29
【问题描述】:

我问了一个类似的问题here(您可能想检查一下)但没有收到答案,所以我将尝试简化它。

#/bin/sh

. /etc/ssh/autossh.conf

if [[ $(ifconfig pdp_ip0 |grep inet) && ! $(ifconfig en0 |grep inet) ]];
then
export NETTEST1=1; echo true
else
export NETTEST1=0; echo false
fi

if [[ ! $(ifconfig pdp_ip0 |grep inet) && $(ifconfig en0 |grep inet) ]];
then
export NETTEST2=1; echo true
else
export NETTEST2=0; echo false
fi

while
test $NETTEST1 -eq 1;
do
echo true
done

while
test $NETTEST2 -eq 1;
do
echo true
done

这段代码的问题是它会在条件为真时继续执行命令。我需要它对每个真语句只执行一次,然后等到该语句为假然后再次为真。我一直在努力解决它,我想知道它是否可能。任何帮助总是受到赞赏。

我应该这样做吗:

    while true; do
    while ifconfig pdp_ip0 |grep inet && ! ifconfig en0 |grep inet;
    do sleep 1; done
    while ! ifconfig pdp_ip0 |grep inet && ifconfig en0 |grep inet; do sleep 1; done
    killall autossh; start-autossh
    done;

【问题讨论】:

  • ifconfig 命令在if 语句中执行一次(并且仅执行一次)。然后脚本将退出(如果 NETTEST1 和 NETTEST2 都为零)或永远循环(如果 NETTEST1 或 NETTEST2 为 1)。
  • 可以,但需要不断检查接口的状况。 echo true 在 while 循环 id put killall 和我正在执行的另一个脚本上。如果我这样做,它将继续不必要地杀死我的脚本。
  • 与问题无关(我不太明白):if [[ ! $(ifconfig pdp_ip0 |grep inet) && $(ifconfig en0 |grep inet) ]]; 不必要地复杂(尽管它会起作用)。你可以更简单地写:if ! ifconfig pdp_ip0 | grep -q inet && ifconfig en0 | grep -q inet; then ...
  • 这确实是一个我正在尝试解决的复杂问题。当其中一个接口关闭然后重新启动它时,我需要检查脚本来杀死二进制文件。问题是它需要每个 true 完成一次。这就是为什么我需要等待返回 false 才能再次执行 true 。这与我的网络接口关闭和 autossh 不知道如何切换到活动接口有关。
  • @Geofferey:iOS 有 /etc/network/if-up.d/etc/network/if-down.d 脚本吗?那将是最简单的解决方案。

标签: bash shell loops networking conditional-statements


【解决方案1】:

您要做的是在“边缘转换”上触发一些命令;也就是条件从假到真的转变。您可以这样做(省略条件和操作的详细信息):

while true; do
  while condition; do sleep 1; done
  while ! condition; do sleep 1; done
  do_what_needs_to_be_done
done;

假设条件(可以是任何管道)不会在不到一秒的时间内来回翻转(或者您不介意在发生这种情况时错过操作),这应该在 @987654323 时执行 do_what_needs_to_be_done @从失败到成功的变化。

这个警告是“边缘转换”被怀疑的原因之一。虽然一秒钟的阈值对于网络向上或向下的变化似乎是可以的,这通常至少需要几秒钟,但您还需要考虑如果设备正在运行,您的脚本可能没有足够频繁地调度的问题在负载下(或睡觉)。但它可能总比没有好。

为了清楚起见,我认为你遇到的问题稍微复杂一些,所以这里有一个更清晰的解决方案:

# Do this forever
while true; do
  # Figure out which interface is up (if any) at the beginning
  if ifconfig en0 | grep -q inet; then IF=en0
    elif ifconfig pdp_ip0 | grep -q inet; then IF=pdp_ip0
    else IF=
  fi

  # Some interface should be up at this point, but if not,
  # there is no point waiting for it to go down.  
  if [[ $IF ]]; then
    while ifconfig $IF | grep -q inet; do sleep 1; done
  fi;
  # Now whatever was up is down. Wait for something to come up.
  while ! ifconfig en0 | grep -q inet && ! ifconfig pdp_ip0 | grep -q inet; do
    sleep 1
  done

  # Some interface is up, so do the dirty deed
  killall autossh; start-autossh
  # And go back to waiting for the interface to drop.
done

【讨论】:

  • 你能检查我的主要帖子,并告诉我是否应该这样做吗?
  • 您可能需要grep -q 而不仅仅是grep,因为您不需要任何输出。但另一个问题是这两个条件并不相反:两个网络接口都可能关闭。我认为您可能想要做的是while true; do while the current network interface is up; do sleep 1; done; while neither interface is up; do sleep 1; done; do_what_needs_to_be_done; done。复杂之处在于知道“当前”网络接口是什么;你会想要一个 shell 变量,其值为 en0pdp_ip0 并相应地设置它。
  • 我现在更困惑了。这是我一段时间以来用 bash 完成的最复杂的事情。当前的网络接口可以是任何时候的任何一个:/我什至还没有找到一种方法来找出哪个是活动的。如果我能找出哪个是活跃的,它会让这种方式更简单。当活动界面发生变化并重新启动时,我可以让它终止 autossh。
  • @Geofferey:你去吧。没那么复杂,老实说。
  • 大声笑,好吧,我会试试看它的作用。顺便说一句,我从来没有使用过 elif... 只是还有一件事可以让您动脑筋...您知道一种方法来检查实际处于活动状态的界面吗?
【解决方案2】:

我真的不明白你想做什么。像这样?

do_test_1() {
    {   ifconfig pdp_ip0 | grep -q inet; } &&
    { ! ifconfig en0     | grep -q inet; }
}

if do_test_1; then
    echo "true once"
    while ! do_test_1; do 
        sleep 60   # or some amount
    done
    echo "true once again"
fi

【讨论】:

  • 你检查链接了吗?它解释了我想要做什么以及为什么。您的看起来它将执行命令并等待 60 秒,如果条件仍然为真,则再次执行。我需要它在 true 上执行一次,然后等待 false 然后再次为 true。顺便说一句,谢谢您的回答,但我不确定它是否会起作用。
猜你喜欢
  • 2018-04-10
  • 2013-12-07
  • 2022-01-02
  • 1970-01-01
  • 2016-06-05
  • 2017-01-07
  • 2020-06-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多