如果另一个APT实例正在运行,如何使包管理器等待?

我见过很多软件,比如Update Manager和Synaptic Package Manager,如果其他程序正在使用/var/lib/dpkg/lock并且被锁定,它们会等待。 我们怎样才能通过航站楼这样做? 我看到了apt-get的手册,但没有找到任何有用的东西。

您可以使用aptdcon命令 Manpage图标 通过与aptdaemon通信而不是直接使用apt-get来排队包管理器任务。

所以基本上你可以做sudo aptdcon --install chromium-browser或者其他什么,当该命令运行时,你可以再次运行它,但是安装不同的软件包,而apt-daemon只是将它们排队而不是错误输出。

如果您正在进行长时间的升级或某些事情并希望继续安装软件包,或者您正在编写某些内容并希望确保安装更可靠,则此function尤其有用。

如果另一个软件管理器正在运行,您可以让apt-get学会等待。 类似于下一个屏幕投射的行为:

在此处输入图像描述

我怎么做的?

我在/usr/local/sbin目录中创建了一个名为apt-getapt-get包装器)的新脚本,其中包含以下bash代码:

 #!/bin/bash i=0 tput sc while fuser /var/lib/dpkg/lock >/dev/null 2>&1 ; do case $(($i % 4)) in 0 ) j="-" ;; 1 ) j="\\" ;; 2 ) j="|" ;; 3 ) j="/" ;; esac tput rc echo -en "\r[$j] Waiting for other software managers to finish..." sleep 0.5 ((i=i+1)) done /usr/bin/apt-get "$@" 

别忘了让它可执行:

 sudo chmod +x /usr/local/sbin/apt-get 

在测试之前,检查一切是否正常。 which apt-get命令的输出现在应该是/usr/local/sbin/apt-get 。 原因是:默认情况下, /usr/local/sbin目录放在用户或根PATH /usr/bin目录之前。

除了显而易见的&& ,你可能正在寻找aptdcon 。 此工具能够检测apt的其他实例并等待它们完成:

  sudo aptdcon --safe-upgrade
 [/] 11% 等待其他软件经理退出等待资质 

(我正在其他地方跑步)

这个工具的优点是你可以连续存储几个动作,而不用担心你接下来会做什么。 aptdcon是无人参与脚本和GUI安装的理想选择,因为您可以允许在后台运行该工具,而不是阻止您的前端。

aptdcon支持的操作是:

  • --refresh-c :这相当于apt-get update 。 它会更新您的包裹清单。
  • --install , – --purge , – --downgrade , – --purge , – --downgrade 。 他们每个人都如他们的名字所说。 包的名称是必需的。 -i-r-u-p :除了降级之外,所有这些都是短期选项,没有降级。
  • --safe-upgrade , – --full-upgradeapt-getupgrade / dist-upgradeaptitudesafe-upgrade / full-upgrade 。 这些不需要参数。
  • 还有其他几项操作,可以在手册中找到。 但是,这些是对aptd感兴趣的用户最常用的。 有些选项与apt-keyapt-cachedpkg重叠。

apt-get本身不支持这样的方法(等待apt的其他实例),因此aptdcon是GUI包管理器的首选解决方案:USC使用aptd作为后端,与Synaptic相同。 其他解决方案是packagekit ,但它不支持您正在寻找的function(尚未)。

一个非常简单的方法是等待锁不能打开的脚本。 我们称之为waitforapt并将其粘贴在/usr/local/bin

 #!/bin/sh while sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do sleep 1 done 

然后只需运行sudo waitforapt && sudo apt-get install whatever 。 您可以在sudoers添加例外,以便您无需密码即可运行它(您需要它才能获得apt-get因此它没有太大的收益)。

不幸的是,这不会排队。 鉴于apt的一些操作是交互式的(“你确定要删除所有这些包吗?!”),我看不出这方面的好方法……

您可以使用轮询技术:

 $ time (while ps -opid= -C apt-get > /dev/null; do sleep 1; done); \ apt-get -y install some-other-package 

我制作了一个脚本来执行此操作:

 #!/bin/bash # File path to watch LOCK_FILE='/var/lib/dpkg/lock' # tput escape codes cr="$(tput cr)" clr_end="$(tput el)" up_line="$(tput cuu 1)" CLEAN(){ # Cleans the last two lines of terminal output, # returns the cursor to the start of the first line # and exits with the specified value if not False echo -n "$cr$clr_end" echo echo -n "$cr$clr_end$up_line" if [[ ! "$1" == "False" ]]; then exit $1 fi } _get_cmdline(){ # Takes the LOCKED variable, expected to be output from `lsof`, # then gets the PID and command line from `/proc/$pid/cmdline`. # # It sets `$open_program` to a user friendly string of the above. pid="${LOCKED#p}" pid=`echo $pid | sed 's/[\n\r ].*//'` cmdline=() while IFS= read -d '' -r arg; do cmdline+=("$arg") done < "/proc/${pid}/cmdline" open_program="$pid : ${cmdline[@]}" } # Default starting value i=0 # Checks if the file is locked, writing output to $FUSER while LOCKED="$(lsof -F p "$LOCK_FILE" 2>/dev/null)" ; do # This will be true if it isn't the first run if [[ "$i" != 0 ]]; then case $(($i % 4)) in 0 ) s='-' i=4 _get_cmdline # Re-checks the command line each 4th iteration ;; 1 ) s=\\ ;; 2 ) s='|' ;; 3 ) s='/' ;; esac else # Traps to clean up the printed text and cursor position trap "CLEAN False; trap - SIGINT ; kill -SIGINT $$" SIGINT trap 'CLEAN $((128+15))' SIGTERM trap 'CLEAN $((128+1))' SIGHUP trap 'CLEAN $((128+3))' SIGQUIT # Default starting character s='-' _get_cmdline echo -n "$save_cur" fi # Prints the 2nd line first so the cursor is at the end of the 1st line (looks nicer) echo echo -n "$cr$clr_end$open_program" echo -n "$up_line$res_cur$cr$clr_end[$s] Waiting for other package managers to finish..." #echo -en "$cr$clr_end[$s] Waiting for other package managers to finish..." #echo -en "\n$cr$clr_end$open_program$cr$up_line" ((i++)) sleep 0.025 done CLEAN False # This allows saving the script under a different name (eg `apt-wait`) # and running it. It only imitates `apt-get` if it was launched as such if [[ "${0##*/}" == 'apt-get' ]]; then exec /usr/bin/apt-get "$@" exit $? fi 

将上面的内容保存到/usr/local/sbin/apt-get 。 如果另一个实例已在运行, apt-get将等待。

或者,将其保存为/usr/local/sbin/apt-wait ,示例用法:

 apt-wait && aptitude 

在持有锁的当前进程退出后将运行aptitude

示例运行:

  1. 首先,运行apt-get命令,例如:

     $ sudo apt-get remove some_package 
  2. 然后,在另一个终端中,运行另一个命令:

     $ sudo apt-get install some_other_package 

    它将等待第一个命令完成然后运行。 等待时输出:

     [/] Waiting for other package managers to finish... 28223 : /usr/bin/apt-get remove some_package 

不幸的是,当您在不同的非特权命名空间容器(如lxc)中运行时,fuser对您没有太多帮助。

此外,默认情况下不会安装aptdcon(至少在18.04),并将您的任务置于队列中,这样就会丢失序列化。 这不是不可克服的,但它确实意味着你的自动化需要有一些方法来避免在安装aptdcon时apt中的flock错误,并且你需要为通过aptdcon安装包后需要序列化的任何东西提供某种等待循环除非已经有某种旗帜。

工作是什么? 这也应该适用于NFS等,因为它以与apt相同的方式使用文件系统锁定,仅使用-w seconds参数,它将在您的锁上等待而不是抛出错误。

因此,按照包装器模型,将其添加为/ usr / local / bin /中的apt-get并共享。

这也有一个好处,就是不允许在apt上进行并行操作来限制IO,这样你就可以让cron在午夜时分触发更新而不会打败磁盘。

 #!/bin/bash exec /usr/bin/flock -w 900 -F --verbose /var/cache/apt/archives/lock /usr/bin/apt-get $@ 

apt-get的一个非常好的和简单的function请求是转换为阻塞/等待锁的-w标志。

基于Oli答案的单线程 :

 while sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do sleep 1; done