Як змусити менеджера пакунків чекати, якщо працює інший екземпляр APT?


50

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


добре, ви можете виконати кілька команд 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-демон просто поставить їх у чергу, а не помилятися.

Це особливо корисно, якщо ви робите довге оновлення чи щось, і хочете продовжувати встановлювати пакети, або якщо ви щось розробляєте разом і хочете переконатися, що встановлення речей буде більш надійним.


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каталозі із таким баш-кодом всередині:

#!/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каталогом у користувачеві або корені PATH.


це дійсно прямий удар до мого питання. дякую :)
— rɑːdʒɑ

2
Як ваш сценарій управляє складеними екземплярами apt-get? Мовляв, до того, як він закінчиться, я запускаю ще 5 підхожих?
— Брайам

@Braiam З повагою, я не знаю; Я не хороший тестер. Ви тестували це? Якщо з’являються проблеми, сценарій можна вдосконалити, створивши новий замок із часовою міткою, коли починається новий екземпляр сценарію (лише приклад - також існує багато інших способів).
— Radu Rădeanu

Оце Так! красномовний. працює як шарм із усім, що я накинув на це досі! Два великих пальця вгору ... це має бути просто частиною пакету: 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. Цей інструмент здатний виявляти інші випадки влучності та чекати їх закінчення:

sudo aptdcon - безпечне оновлення
[/] 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Сам по собі не підтримує таких методів (чекати інших примірників), тому aptdconє кращим рішенням для менеджерів пакетів GUI: USC використовує aptdяк бек-енд, як Synaptic. Інше рішення є packagekit, але воно не підтримує функцію, яку ви шукаєте (поки).


1
aptdcon --install /path/to/pgk.debПрацює на кшталт dpkg -i, хоча я не зміг знайти це прямо вказане в посібнику.
— whitehat101

Чи можу я використовувати це в сценарії після встановлення в пакеті?
— Нельсон Тейшейра

@NelsonTeixeira, чому б ти використовував це у сценарії ppst-install? Якщо після встановлення виконується, очевидно, працює apt.
— Брайам

Я хочу змусити після встановлення встановити деякі спеціальні пакети, яких немає у сховищі. Чи можливо це? Я б включив їх у пакет, і тоді сценарій встановив би їх після завершення встановлення.
— Нельсон Тейшейра

@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припустити, що так для всіх операцій?
— Брайам

Дякую. Я думаю, що я можу скористатися нею краще, якщо скористаюся допомогою псевдоніма.
— rɑːdʒɑ

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
— Manuel Kießling

3

Ви можете використовувати техніку опитування:

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

краще використовувати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) і фоновим завданням є в черзі, щоб ви втратили серіалізацію. Це не є непереборним, але це означає, що ваша автоматизація повинна мати певний спосіб уникнути помилок зграї в apt під час встановлення aptdcon, і вам потрібно буде мати певні петлі очікування для всього, що потрібно для серіалізації після встановлення пакетів через aptdcon якщо тільки для цього вже немає якогось прапора.

Те, що працює, є отари. Це також має працювати над NFS і т. Д., Оскільки він використовує блокування файлової системи так само, як це робиться, лише з параметром -w секунд він буде чекати на ваш замок, а не видавати помилку.

Отже, слідуючи моделі обгортки, додайте це як apt-get in / usr / local / bin / та поділіться подалі.

Це також має перевагу обмеження IO, не дозволяючи паралелізму на 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замок набувається, а потім передається цільовому процесу, тому він не залишає часу для втрати блокування тим часом.
— jrudolph

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.