Как заставить менеджер пакетов ждать, если запущен другой экземпляр APT?

50

Я видел много программ, таких как Update Manager и Synaptic Package Manager, они ждут, если какая-то другая программа использует /var/lib/dpkg/lockи заблокирована. Как мы можем сделать это через Терминал? Я видел apt-getруководство, но не нашел ничего полезного.

Piyush
источник
ну, вы можете сделать несколько команд apt-get. Как sudo apt-get install packagename && sudo apt-get updateи они будут происходить автоматически после друг друга.
Альвар
1
Разве это не делает это sudo apt-get install packagename1 packagename2 packagename3 ?
Rinzwind
(См. Unix.stackexchange.com/questions/463498/…, если вы находитесь в особом случае, когда вы пытаетесь дождаться окончания загрузки в Ubuntu 18.04 и более поздних версиях )
Anon

Ответы:

35

Вы можете использовать в aptdconкомандуЗначок Manpage в очереди диспетчера пакетов задач, связываясь с aptdaemon вместо того , чтобы использовать APT-получить непосредственно.

Таким образом, в основном вы можете просто делать sudo aptdcon --install chromium-browserчто угодно, и пока эта команда выполняется, вы можете запустить ее снова, но установить разные пакеты, и apt-daemon просто поставит их в очередь, а не выдает ошибку.

Это особенно полезно, если вы делаете длительное обновление или что-то еще и хотите продолжать устанавливать пакеты, или если вы что-то пишете вместе и хотите убедиться, что установка будет более надежной.

Хорхе Кастро
источник
4
Может aptdconбыть запущен так, что он принимает любые запросы, как это apt-get -yделает?
Ноки
4
yes | aptdcon --hide-terminal --install "package"Скрыть терминал необходим, иначе трубопровод yesвызовет проблемы.
whitehat101
1
Проблема с этим ответом заключается в том, что он требует установки aptdcon. Я работаю над скриптом начальной загрузки, который выполняет начальную настройку VPS, где фоновый процесс также выполняет некоторые начальные настройки. Я не могу установить, aptdconпока не смогу обойти замок.
Фальшивое имя
2
@FakeName для начальной конфигурации сервера, которую вы, вероятно, хотите использовать cloud-init: cloudinit.readthedocs.io/en/latest
Хорхе Кастро,
1
в какой упаковке aptdcon?
Ctrl-Alt-Delor
45

Вы можете 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.

Раду Рэдяну
источник
это действительно прямой удар по моему вопросу. спасибо :)
rʒɑdʒɑ
2
Как ваш скрипт управляет сложенными экземплярами apt-get? Мол, прежде чем он закончится, я запускаю еще 5 apt-get?
Брайам
@Braiam С уважением, я не знаю; Я не хороший тестер. Вы проверяли это? Если возникают проблемы, сценарий может быть улучшен путем создания новой блокировки с отметкой времени при запуске нового экземпляра сценария (просто пример - есть также много других способов).
Раду Рэдяну
Вау! красноречив. работает как шарм со всем, что я бросил в него до сих пор! Два больших пальца вверх ... это должно быть частью пакета: D
Эрик
2
Отлично! У меня была проблема, когда я использую AWS cloudinit для установки пакетов на новый сервер, но Ubuntu делает некоторые aptвещи при загрузке, поэтому моя dpkgкоманда завершилась неудачно из-за заблокированного dpkg db. Я поместил эту однострочную строку в свои пользовательские данные cloudinit: while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 1; done; dpkg -i package.debи она прекрасно работает.
Владимир Смотеско
20

Помимо очевидного &&, вы можете искать 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's upgrade/ dist-upgradeи aptitude' s safe-upgrade/ full-upgrade. Это не нуждается в параметрах.
  • Есть несколько других операций, которые можно найти в руководстве. Но они наиболее часто используются заинтересованными пользователями aptd. Есть варианты, которые пересекаются с тем apt-key, что apt-cache, dpkgделать.

apt-getсама по себе не поддерживает такие методы (для ожидания других экземпляров apt), поэтому aptdconявляется предпочтительным решением для менеджеров пакетов GUI: USC использует aptdкак back-end, так же как Synaptic. Другое решение packagekit, но оно не поддерживает функцию, которую вы ищете (пока).

Braiam
источник
1
aptdcon --install /path/to/pgk.debРаботает как dpkg -i, хотя я не смог найти это явно упоминается в руководстве.
whitehat101
Могу ли я использовать это в послеустановочном скрипте в пакете?
Нельсон Тейшейра
@NelsonTeixeira, почему вы используете это в сценарии ppst-install? Если после установки выполняется, очевидно, что apt работает.
Брайам
Я хочу заставить postinstall установить некоторые специальные пакеты, которых нет в репозитории. Это возможно ? Я включил бы их в пакет, а затем скрипт установил бы их после завершения установки.
Нельсон Тейшейра
Снова @NelsonTeixeira, зачем это нужно? Сценарии после установки запускаются только при установке пакета. Я предлагаю вам задать вопрос и объяснить ваш случай более подробно.
Брайам
18

Очень простым подходом будет сценарий, который ожидает, пока блокировка не будет открыта. Давайте назовем это 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предположить да для всех операций?
Брайам
Спасибо. Я думаю, что я могу использовать его лучше, если я использую помощь псевдонима.
r13d '
3
Не уверен, что -yжелательно, хотя.
Оли
1
Я не думаю , что вы хотите , чтобы обернуть sudo fuserв [[ $(...) ]]. Он возвращает нулевой код завершения при доступе к файлу, поэтому этого должно быть достаточно.
Кири
4
Я нашел следующее решение более полным, так как при работе с apt-get задействовано несколько блокировок: 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
Мануэль Кисслинг
3

Вы можете использовать технику опроса:

$ time (while ps -opid= -C apt-get > /dev/null; do sleep 1; done); \
  apt-get -y install some-other-package
Malthe
источник
лучше использоватьinotify
ctrl-alt-delor
3

Я сделал скрипт, который делает это:

#!/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после завершения текущего процесса, удерживающего блокировку.

Пример выполнения:

  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
    
харакири
источник
1
лучше использоватьinotify
ctrl-alt-delor
3

К сожалению, fuser мало что делает для вас, когда вы работаете в разных непривилегированных контейнерах пространства имен, таких как lxc.

Кроме того, aptdcon не устанавливается по умолчанию (по крайней мере, 18.04) и помещает вашу задачу в очередь, поэтому вы теряете сериализацию. Это не является непреодолимым, но это означает, что ваша автоматизация должна иметь какой-то способ избежать ошибок flock в 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 для переключения на блокировку / ожидание блокировки.

Рэймонд Фергюсон
источник
apt использует fcntl, а не flock, так что это не сработает. askubuntu.com/questions/1077215/…
Энди
Это работает отлично и является лучшим вариантом, чем использование, fuserкак показано во многих ответах, потому что fuserвсе еще склонен к гонкам между просмотром блокировки и целевым процессом, снова захватившим блокировку. С flockблокировкой получается, а затем передается целевому процессу, поэтому у него не остается времени для потери блокировки в это время.
Джрудольф
1

Однострочник на основе ответа Оли :

while sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do sleep 1; done
Менашех
источник