【问题标题】:repeat bash command infinitely, but only when the previous bash command has finished无限重复 bash 命令,但仅在前一个 bash 命令完成时
【发布时间】:2018-10-28 16:14:50
【问题描述】:

在我们用于构建的 macOS 虚拟机上,有时会无缘无故地跳出时间。作为一种解决方法,我创建了这个名为 test.sh 的脚本,它始终如一地更正时间:

#!/bin/bash -e

while true; do
    sudo ntpdate -u de.pool.ntp.org >> ntpdate.txt; sleep 30;
done

在构建开始时,它会在后台启动:

./test.sh &

当构建完成时,我正在杀死它:

kill $(ps aux | grep test.sh | grep -v grep | awk '{print $2}')

有时调用更新时间需要超过 30 秒。然后有两个对 ntp 池的开放调用,我得到了速率限制响应。因此,我想将对 ntp 的调用限制为一次只能调用一个。如何在我的 while true 循环中实现这一点?

【问题讨论】:

  • 你可以试试kill %1pkill -f test.sh -u $USER 来代替复杂的grep/grep/awk 的东西。
  • 您的构建过程不必担心设置时间。将 VM 配置为通过launchd 以所需的时间间隔运行 ntpdate,并让构建过程假定时钟正确。
  • 您的代码已经仅在上一个命令完成时继续执行...除非您同时进行两个单独的构建,从而运行两个独立的循环。
  • ...处理两个独立构建的情况,请参阅Linux flock, how to “just” lock a file?
  • 这应该会有所帮助...stackoverflow.com/a/37303133/2836621

标签: bash ntp


【解决方案1】:

在 Bash 中实现互斥的一种简单方法是使用“锁定文件”。检查文件是否存在,如果存在,则不执行 NTP 查询。如果文件不存在,则创建它。如果发生崩溃,一个有用的增强功能是检查文件时间是否超过几分钟,在这种情况下可以将其删除。

【讨论】:

  • 这样做有很多危险——一个简单的实现可能有两个并发实例都看到没有文件,并同时独立地继续执行创建的行。为了安全起见,确实应该使用flock 进行锁定,使用其他谨慎使用O_CREAT|O_EXCL 或目录语义的工具(安全性稍差,但可移植性稍好)。
  • @CharlesDuffy:当然,一个简单的 lockfile 实现并不完美,但我敢打赌它对于 OP 的实际用例来说已经足够好了。但你是对的,flock(1) 是一个很好用的工具。
【解决方案2】:

您能否尝试查看以下是否适用于您的情况。

#!/bin/bash

while true; do
  pid=0
  sudo ntpdate -u de.pool.ntp.org >> ntpdate.txt & pid=(${!})
  wait $pid
done

【讨论】:

  • 这与首先不将进程置于后台并因此在流控制成功之前自动/默认情况下等待其退出有何不同?
  • (使pid 成为一个数组也有点奇怪——当然,$pid 在给定一个数组时会计算第一个元素,但如果你只想先引用它元素,为什么不将数据类型保留为字符串?)
【解决方案3】:

感谢所有建议。正如 Charles Duffy 提到的,我的代码只有在前一个命令完成时才会继续。我已经测试过了:

#!/bin/bash -e

while true; do
    echo "start ntpdate"
    sudo ntpdate -u de.pool.ntp.org >> ntpdate.txt; 
    echo "going to sleep"
    sleep 30;
done

显然,睡眠计时器太低而无法进入速率限制响应。也许我必须提高睡眠时间。

正如 chepner 建议的那样,我创建了一个 LaunchAgent 来处理这个问题:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>workaroundAgainstJumpingTime</string>
    <key>ProgramArguments</key>
    <array>
        <string>sudo</string>
        <string>ntpdate</string>
        <string>-u</string>
        <string>de.pool.ntp.org</string>
    </array>
    <key>RunAtLoad</key>
    <true/>
    <key>StandardErrorPath</key>
    <string>/tmp/workaroundAgainstJumpingTime.stderr</string>
    <key>StandardOutPath</key>
    <string>/tmp/workaroundAgainstJumpingTime.stdout</string>
    <key>StartInterval</key>
    <integer>30</integer>
</dict>
</plist>

Charles Duffy,如果您从您的评论中回答“您的代码仅在上一个命令完成后才继续执行。”我会将其标记为已接受的答案。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-19
    • 1970-01-01
    • 2021-06-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多