【问题标题】:Detecting/avoiding multiple apt-get/dpkg installs检测/避免多个 apt-get/dpkg 安装
【发布时间】:2014-06-29 21:50:11
【问题描述】:

我有新用户用来配置系统的脚本,基本上是一个带有大 for 循环的 bash 脚本,如下所示:

DEBCOUNT=${#DEBS[@]}
for (( i=0; i<${DEBCOUNT}; i++ ));
do
  PACKAGE=${DEBS[$i]}
  dpkg -s ${PACKAGE} >> /dev/null
  if [ ${PIPESTATUS[0]} -ne 0 ]; then
    echo -n  =========== Installing ${PACKAGE}
    echo "  ( $((${i}*100/${DEBCOUNT}))% )"

    apt-get -qq install -y --force-yes  ${PACKAGE}
    if [ $? -ne 0 ]; then
      echo ERROR: Failed to install required package ${PACKAGE}
      exit 1
    fi
  else
    echo -n  =========== Skipping ${PACKAGE}
    echo "  ( $((${i}*100/${DEBCOUNT}))% )"
  fi
done

DEBS 大数组是要在新系统(主要是编译器和编辑器)上安装的 50 个包的列表。

它工作得很好,除非某些系统进程启动并开始在后台更新 APT 数据库。然后它以dpkg: error: dpkg status database is locked by another process 失败。

是否有一种优雅/稳健的方法来避免此错误?要么通过检测它并以某种方式等待它空闲,要么通过首先阻止它。

回复

  • 我不想只删除锁定文件。尝试安装我的东西以及系统同时执行的任何操作都会不可避免地破坏某些东西。
  • 我无法在启动时进行一次检查,因为我所看到的似乎表明另一个进程正在进行我想要的那种等待,并在我的两个进程之间跳转apt-get的。
  • 锁定的不是单个进程。有时我认为是 ubuntu 软件更新程序,有时我认为这是 cron 运行大型 apt-get update 的工作。

【问题讨论】:

  • 为什么不使用apt-get 一次性使用所有包,而不是一个接一个地安装包?此外,--force-yes 肯定是我将永远避免的事情,因为您在强行通过时会忽略潜在的问题。
  • 你不能在 Ubuntu 上同时安装两个包。
  • 大命令是最初的设计,但是一些包来自 PPA,如果安装失败,系统就会处于奇怪的状态。用户最终只安装了一半的包,一半没有,而且要弄清楚哪些丢失了并不容易。这更安全(尽管速度较慢)。
  • @avinash Duh .. 这就是问题的重点.. 我如何防止另一个进程这样做?或者我如何检测它,并知道它何时是安全的?
  • 不确定这有多有效,但尝试在for 循环中的apt-get ... 命令之前立即运行rm -f /var/lib/dpkg/lock。这样,您将在运行包安装之前杀死锁(如果有的话)。

标签: bash ubuntu debian apt dpkg


【解决方案1】:

我带着同样的问题来到这里,想检测apt-getdpkg 使用的锁定文件是否被锁定,不管这是否是最相关的测试(在我的情况下)。我最终使用了以下 Python 代码 sn-p:

import fcntl

def is_dpkg_active():
    """
    Check whether ``apt-get`` or ``dpkg`` is currently active.

    This works by checking whether the lock file ``/var/lib/dpkg/lock`` is
    locked by an ``apt-get`` or ``dpkg`` process, which in turn is done by
    momentarily trying to acquire the lock. This means that the current process
    needs to have sufficient privileges.

    :returns: ``True`` when the lock is already taken (``apt-get`` or ``dpkg``
              is running), ``False`` otherwise.
    :raises: :py:exc:`exceptions.IOError` if the required privileges are not
             available.

    .. note:: ``apt-get`` doesn't acquire this lock until it needs it, for
              example an ``apt-get update`` run consists of two phases (first
              fetching updated package lists and then updating the local
              package index) and only the second phase claims the lock (because
              the second phase writes the local package index which is also
              read from and written to by ``dpkg``).
    """
    with open('/var/lib/dpkg/lock', 'w') as handle:
        try:
            fcntl.lockf(handle, fcntl.LOCK_EX | fcntl.LOCK_NB)
            return False
        except OSError:
            return True

【讨论】:

  • IOError 现在应该是 OSError:在 3.3 版中更改:此模块中的操作用于引发 IOError,现在它们会引发 OSError。 docs.python.org/3/library/fcntl.html
  • 我已将代码示例更新为使用OSError 而不是IOError,感谢@falcojr 的建议!
【解决方案2】:

@tripleee 的答案是最好的,但如果由于某种原因你不能这样做(我知道在极少数情况下这是真的——因为它发生在我们身上),正确的做法是发出单个命令,而不是使用循环:

apt-get -qq install -y --force-yes $DEBS

【讨论】:

  • 嗯,这仍然不能解决主要问题:如果软件更新程序或 cron 作业在后台更新 APT 数据库,即使是单个大规模 apt-get 也会失败。有没有办法检测到 APT 已经在使用中并等待?
  • 那么,最好的选择是循环运行,如果检测到失败,再试一次。如果检测到成功,则退出循环。
  • 有些失败是灾难性的:(无法解决依赖关系,服务器关闭等)..我只想检测一个简单的:(无法获得锁)。
  • @Yeraze:您可以通过检查 apt-get 和 grepping 的错误输出来确定这一点,例如,单词“lock”
【解决方案3】:

正确的解决方案是用你想要安装的所有其他包中的Depends: 的虚拟包替换你的复杂脚本。

equivs 包是构建这种虚拟包的一种简单(尽管起初不是很直观)的方法。

顺便说一句,这不是临时黑客;这就是例如Debian build-essential 包引入了整个构建链。

【讨论】:

  • 您能多谈谈“取决于:”设置吗?那是某个地方的配置吗?那是一些特殊的包装设置吗?我如何使用它或在哪里可以找到更多信息?
  • 这是您构建的包源中debian/control 文件中的声明。真的,看看equivs documentation
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-07-31
  • 1970-01-01
  • 1970-01-01
  • 2013-08-03
相关资源
最近更新 更多