Как заставить менеджер пакетов ждать, если запущен другой экземпляр APT?
Я видел много программ, таких как Update Manager и Synaptic Package Manager, они ждут, если какая-то другая программа использует /var/lib/dpkg/lock
и заблокирован. Как мы можем сделать это через Терминал? Я видел apt-get
Руководство, но ничего полезного не нашел.
10 ответов
Вы можете использовать aptdcon
команда ставить в очередь задачи диспетчера пакетов, связываясь с aptdaemon вместо непосредственного использования apt-get.
Так что в основном вы можете просто сделать sudo aptdcon --install chromium-browser
или что-то еще, и пока эта команда выполняется, вы можете запустить ее снова, но установить разные пакеты, и apt-daemon просто поставит их в очередь, а не выдает ошибку.
Это особенно полезно, если вы делаете длительное обновление или что-то еще и хотите продолжать устанавливать пакеты, или если вы что-то пишете вместе и хотите убедиться, что установка будет более надежной.
Ты можешь сделать apt-get
научиться ждать, если другой менеджер программного обеспечения работает. Нечто подобное с поведением из следующего скриншота:
Как я это сделал?
Я создаю новый скрипт с именем apt-get
(обертка для apt-get
) в /usr/local/sbin
каталог со следующим кодом 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
каталог размещен перед /usr/bin
каталог пользователя или root PATH
,
Очень простым подходом будет сценарий, который ожидает, пока блокировка не будет открыта. Давайте назовем это 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 являются интерактивными ("Вы уверены, что хотите удалить все эти пакеты?!"), я не могу найти хороший способ обойти это...
Помимо очевидного &&
, вы можете искать aptdcon
, Этот инструмент может обнаружить другие экземпляры apt и дождаться их завершения:
sudo aptdcon --safe-upgrade [/] 11% В ожидании выхода других менеджеров программного обеспечения В ожидании способности
(Я работаю в другом месте)
Преимущество этого инструмента заключается в том, что вы можете хранить несколько действий подряд, не беспокоясь о том, что вы будете делать дальше. aptdcon
идеально подходит для автоматических сценариев и установки с графическим интерфейсом, поскольку вы можете позволить инструменту работать в фоновом режиме, чтобы не блокировать ваш веб-интерфейс.
Операции, поддерживаемые aptdcon
являются:
--refresh
,-c
: Это эквивалентноapt-get update
, Он обновляет ваш список пакетов.--install
,--remove
,--upgrade
,--purge
,--downgrade
, Каждый из них делает, как говорят их имена. Название пакета (ов) является обязательным.-i
,-r
,-u
,-p
: это короткие варианты для всех, кроме рейтинга, у которого его нет.--safe-upgrade
,--full-upgrade
являются аналогамиapt-get
"supgrade
/dist-upgrade
а такжеaptitude
"ssafe-upgrade
/full-upgrade
, Это не нуждается в параметрах.- Есть несколько других операций, которые можно найти в руководстве. Но это наиболее используемые пользователи, заинтересованные в
aptd
, Есть варианты, которые совпадают с тем, чтоapt-key
,apt-cache
,dpkg
делать.
apt-get
сам не поддерживает такие методы (ждать других экземпляров apt), поэтому aptdcon
является предпочтительным решением для менеджеров пакетов GUI: USC использует aptd
как back-end, такой же как Synaptic. Другое решение packagekit
, но он не поддерживает функцию, которую вы ищете (пока).
С 1.9.11
apt
а также
apt-get
есть опция, позволяющая дождаться освобождения блокировок dpkg.
Использовать
DPkg::Lock::Timeout
возможность установить время ожидания в секундах для команды apt-get. Этот пример будет ждать 60 секунд:
sudo apt-get -o DPkg::Lock::Timeout=60 install packagename
Если вы установите это значение равным -1, оно будет ждать вечно.
sudo apt-get -o DPkg::Lock::Timeout=-1 install packagename
Для получения дополнительной информации см.: Ожидание блокировок apt без хакерских скриптов bash . Эта опция была добавлена в apt-get в феврале 2020 года .
Однострочник на основе ответа Оли:
while sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do sleep 1; done
Вы можете использовать технику опроса:
$ time (while ps -opid= -C apt-get > /dev/null; do sleep 1; done); \
apt-get -y install some-other-package
К сожалению, fuser мало что делает для вас, когда вы работаете в разных непривилегированных контейнерах пространства имен, таких как lxc.
Кроме того, aptdcon не устанавливается по умолчанию (по крайней мере, 18.04) и помещает вашу задачу в очередь, поэтому вы теряете сериализацию. Это не является непреодолимым, но это означает, что ваша автоматизация должна иметь какой-то способ избежать ошибок в apt при установке aptdcon, и вам понадобятся циклы ожидания для всего, что вам нужно сериализовать после установки пакетов через aptdcon если для этого уже нет какого-то флага.
Что работает, так это стадо. Это также должно работать через NFS и т. Д., Поскольку он использует блокировку файловой системы точно так же, как и apt, только с параметром -w секунд он будет ожидать блокировки, а не выдавать ошибку.
Поэтому, следуя модели оболочки, добавьте это как apt-get в /usr/local/bin/ и поделитесь.
Это также имеет преимущество в ограничении ввода-вывода, так как не допускает параллелизма в apt, так что вы можете позволить cron запускать обновления в полночь везде, не перегружая диск.
#!/bin/bash
exec /usr/bin/flock -w 900 -F --verbose /var/cache/apt/archives/lock /usr/bin/apt-get $@
Очень хорошим и простым запросом функции для apt-get будет флаг -w для переключения на блокировку / ожидание блокировки.
Я сделал скрипт, который делает это:
#!/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
В зависимости от того, переносите ли вы все обращения к
apt-get
или нет, это может сработать:
flock ./apt.lock apt-get install ...
Создайте свой собственный замок с
flock(1)
вместо того, чтобы пытаться перехватить различные
dpkg
замки.