Як змусити менеджера пакунків чекати, якщо працює інший екземпляр 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.