我已经看到了许多软件,例如Update Manager和Synaptic Package Manager,它们在其他程序正在使用/var/lib/dpkg/lock
和时被锁定。我们如何通过终端做到这一点?我看到了apt-get
的手册,但没有发现任何有用的信息。
sudo apt-get install packagename1 packagename2 packagename3
吗?
我已经看到了许多软件,例如Update Manager和Synaptic Package Manager,它们在其他程序正在使用/var/lib/dpkg/lock
和时被锁定。我们如何通过终端做到这一点?我看到了apt-get
的手册,但没有发现任何有用的信息。
sudo apt-get install packagename1 packagename2 packagename3
吗?
Answers:
您可以使用该aptdcon
命令通过与aptdaemon通信而不是直接使用apt-get来使程序包管理器任务排队。
因此,基本上您可以执行sudo aptdcon --install chromium-browser
任何操作,并且在该命令运行时可以再次运行它,但是安装不同的软件包,而apt-daemon只会将它们排队,而不是出错。
如果您要进行长期升级或执行某些操作,并且希望继续安装软件包,或者要一起编写脚本,并希望确保安装内容将更加可靠,则此功能特别有用。
aptdcon
运行以使其接受任何提示apt-get -y
吗?
yes | aptdcon --hide-terminal --install "package"
需要Hide Terminal,否则管道yes
会引起问题。
aptdcon
。我正在做一个引导脚本,该脚本执行VPS的初始设置,其中后台进程也在执行一些初始设置。aptdcon
在解决锁定问题之前,我无法安装。
aptdcon
?
apt-get
如果正在运行其他软件管理器,则可以学习等待。与下一个屏幕投射的行为类似:
我在目录中使用以下bash代码创建了一个名为apt-get
(为的包装apt-get
)的新脚本/usr/local/sbin
:
#!/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
命令的输出应为now /usr/local/sbin/apt-get
。原因是:默认情况下,目录在user或root中位于/usr/local/sbin
目录之前。/usr/bin
PATH
apt
在启动时会做一些事情,因此dpkg
由于dpkg db锁定,我的命令失败了。我已经在Cloudinit用户数据中添加了这种单行代码:while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 1; done; dpkg -i package.deb
它非常有用。
除了显而易见的以外&&
,您可能正在寻找aptdcon
。此工具能够检测apt的其他实例并等待它们完成:
sudo aptdcon-安全升级 [/] 11%等待其他软件经理退出等待能力
(我在其他地方有能力)
该工具的优点是您可以连续存储多个操作,而不必担心接下来要做什么。aptdcon
非常适合无人参与脚本和GUI安装,因为您可以允许该工具在后台运行,以免阻塞您的前端。
支持的操作aptdcon
有:
--refresh
,-c
:相当于apt-get update
。它会更新您的包裹清单。--install
,--remove
,--upgrade
,--purge
,--downgrade
。他们每个人都照他们的名字说的做。包装名称是必填项。-i
,-r
,-u
,-p
:这些都是所有除降级,谁不有一个短的选项。--safe-upgrade
,--full-upgrade
是同行apt-get
的upgrade
/ dist-upgrade
和aptitude
的safe-upgrade
/ full-upgrade
。这些不需要参数。aptd
。有迹象表明,什么重叠选项apt-key
,apt-cache
,dpkg
做的。apt-get
本身不支持此类方法(以等待apt的其他实例),因此aptdcon
GUI的程序包管理器的首选解决方案也是如此:USC aptd
用作后端,与Synaptic相同。其他解决方案是packagekit
,但它不支持您正在寻找的功能(尚未)。
aptdcon --install /path/to/pgk.deb
像一样工作dpkg -i
,尽管我找不到手册中明确提到的内容。
一种非常简单的方法是等待锁未打开的脚本。让我们对其进行调用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的某些操作是交互式的(“您确定要删除所有这些软件包吗?!”),所以我看不出解决此问题的好方法...
-y
对所有操作都假设是?
-y
虽然不确定是否可取。
sudo fuser
在[[ $(...) ]]
。当文件被访问时,它返回零退出代码,这样就足够了。
while sudo fuser /var/lib/dpkg/lock /var/lib/apt/lists/lock /var/cache/apt/archives/lock >/dev/null 2>&1; do echo 'Waiting for release of dpkg/apt locks'; sleep 5; done; sudo apt-get -yy update
您可以使用一种轮询技术:
$ time (while ps -opid= -C apt-get > /dev/null; do sleep 1; done); \
apt-get -y install some-other-package
inotify
我做了一个脚本来做到这一点:
#!/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 (e.g. `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
在当前持有锁的进程退出后运行。
示例运行:
首先,
apt-get
运行命令,例如:$ sudo apt-get remove some_package
然后,在另一个终端中,运行另一个命令:
$ sudo apt-get install some_other_package
它将等待第一个命令完成然后运行。等待时输出:
[/] Waiting for other package managers to finish... 28223 : /usr/bin/apt-get remove some_package
inotify
不幸的是,当您在不同的非特权名称空间容器(例如lxc)中运行时,fuser并不会为您带来很多帮助。
另外,默认情况下未安装aptdcon(至少在18.04上安装),并且使任务在队列中后台运行,从而导致序列化丢失。这不是无法克服的,但这确实意味着您的自动化需要某种方式来避免在安装aptdcon时apt中出现群发错误,并且您需要某种等待循环,以便通过aptdcon安装软件包后需要序列化的任何东西除非已经有某种标志。
起作用的是羊群。这也应该在NFS等上工作,因为它以与apt相同的方式使用文件系统锁定,仅使用-w seconds参数,它将等待您的锁定而不抛出错误。
因此,遵循包装模型,将其作为apt-get添加到/ usr / local / bin /中并共享。
通过不允许apt上的并行性,这还具有限制IO的好处,因此您可以让cron在任何午夜的任何地方触发更新而不会破坏磁盘。
#!/bin/bash
exec /usr/bin/flock -w 900 -F --verbose /var/cache/apt/archives/lock /usr/bin/apt-get $@
对apt-get的非常好且简单的功能请求将是-w标志,以切换到阻止/等待锁。
fuser
许多答案中所示的用法相比,此方法效果很好,并且是一个更好的选择,因为fuser
它仍然易于在观察锁和目标进程再次抓住锁之间发生竞争。有了flock
锁后,该锁便被获取,然后传递给目标进程,因此在此期间没有时间丢失锁。
sudo apt-get install packagename && sudo apt-get update
,它们会彼此自动发生。