Jak zmusić menedżera pakietów do czekania, jeśli działa inne wystąpienie APT?

50

Widziałem wiele programów, takich jak Menedżer aktualizacji i Menedżer pakietów Synaptic, czekają, czy jakiś inny program używa /var/lib/dpkg/locki jest zablokowany. Jak możemy to zrobić za pośrednictwem terminalu? Widziałem apt-getinstrukcję, ale nie znalazłem nic przydatnego.

Piyush
źródło
możesz wykonać kilka poleceń apt-get. Polubią sudo apt-get install packagename && sudo apt-get updatei będą następować automatycznie po sobie.
Alvar,
1
Czy to nie robi tego sudo apt-get install packagename1 packagename2 packagename3 :?
Rinzwind,
(Patrz unix.stackexchange.com/questions/463498/…, jeśli jesteś w specjalnym przypadku, w którym próbujesz czekać na czas rozruchu, który kończy się na Ubuntu 18.04 i nowszych)
Anon

Odpowiedzi:

35

Możesz użyć tego aptdconpolecenia,Ikona strony aby ustawić w kolejce zadania menedżera pakietów, komunikując się z aptdaemon, zamiast bezpośrednio używać apt-get.

Zasadniczo możesz to zrobić sudo aptdcon --install chromium-browserlub cokolwiek, a podczas działania tego polecenia możesz je uruchomić ponownie, ale zainstaluj różne pakiety, a apt-daemon po prostu ustawi je w kolejce zamiast błędu.

Jest to szczególnie przydatne, jeśli wykonujesz długą aktualizację lub coś takiego i chcesz nadal instalować pakiety lub jeśli tworzysz coś razem i chcesz mieć pewność, że instalacja będzie bardziej niezawodna.

Jorge Castro
źródło
4
Czy aptdconmożna uruchomić tak, aby akceptował wszelkie monity, tak jak apt-get -yrobi?
Noki,
4
yes | aptdcon --hide-terminal --install "package"Ukryj terminal jest potrzebny, w przeciwnym razie rurociągi yesspowodują problemy.
whitehat101
1
Problem z tą odpowiedzią polega na tym, że wymaga instalacji aptdcon. Pracuję nad skryptem ładowania początkowego, który wykonuje początkową konfigurację VPS, w której proces w tle również wykonuje wstępną konfigurację. Nie mogę zainstalować, aptdcondopóki nie będę mógł obejść blokady.
Fałszywe imię
2
@FakeName dla początkowej konfiguracji serwera prawdopodobnie chcesz użyć cloud-init: cloudinit.readthedocs.io/en/latest
Jorge Castro
1
w której paczce jest aptdcon?
ctrl-alt-delor
45

Możesz apt-getnauczyć się czekać, jeśli działa inny menedżer oprogramowania. Coś podobnego do zachowania z następnej obsady ekranu:

wprowadź opis zdjęcia tutaj

Jak to zrobiłem?

Tworzę nowy skrypt o nazwie apt-get(otoki dla apt-get) w /usr/local/sbinkatalogu z następującym kodem 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 "$@"

Nie zapomnij, aby uczynić go wykonywalnym:

sudo chmod +x /usr/local/sbin/apt-get

Przed przetestowaniem sprawdź, czy wszystko jest w porządku. Wyjście which apt-getpolecenia powinno być teraz /usr/local/sbin/apt-get. Powodem jest: domyślnie /usr/local/sbinkatalog jest umieszczony przed /usr/binkatalogiem użytkownika lub użytkownika root PATH.

Radu Rădeanu
źródło
to naprawdę bezpośredni hit mojego pytania. dzięki :)
rɑːdʒɑ
2
Jak twój skrypt zarządza skumulowanymi instancjami apt-get? Na przykład, zanim to się skończy, uruchamiam jeszcze 5 apt-get?
Braiam
@Braiam Z poważaniem, nie wiem; Nie jestem dobrym testerem. Testowałeś to? Jeśli pojawią się problemy, skrypt można ulepszyć, tworząc nową blokadę ze znacznikiem czasu, gdy rozpoczyna się nowa instancja skryptu (tylko przykład - jest też wiele innych sposobów).
Radu Rădeanu
łał! wymowny. działa jak urok ze wszystkim, co do tej pory do niego rzuciłem! Dwa kciuki do góry ... to powinna być tylko część pakietu: D
Eric
2
To idealne! Miałem problem z korzystaniem z AWS cloudinit do instalowania pakietów na nowym serwerze, ale Ubuntu robi kilka aptrzeczy podczas uruchamiania, więc moje dpkgpolecenie nie powiodło się z powodu zablokowanego dbkg db. Umieściłem ten jeden wiersz w moich danych użytkownika cloudinit: while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 1; done; dpkg -i package.debi działa świetnie.
Volodymyr Smotesko
20

Oprócz tego &&, czego możesz szukać aptdcon. To narzędzie jest w stanie wykryć inne przypadki apt i poczekać, aż zakończą:

sudo aptdcon - bezpieczne uaktualnienie
[/] 11% Oczekiwanie na rezygnację innych menedżerów oprogramowania Oczekiwanie na umiejętności

(Prowadzę aptitude gdzie indziej)

Zaletą tego narzędzia jest to, że możesz przechowywać kilka działań kolejno, nie martwiąc się tym, co będziesz robić dalej. aptdconjest idealny do skryptów nienadzorowanych i instalacji GUI, ponieważ możesz pozwolić narzędziu działać w tle, aby nie blokować interfejsu użytkownika.

Obsługiwane operacje aptdconto:

  • --refresh, -c: Jest to odpowiednik apt-get update. Aktualizuje listę pakietów.
  • --install, --remove, --upgrade, --purge, --downgrade. Każdy z nich robi, jak mówią ich imiona. Nazwa paczki jest obowiązkowa. -i, -r, -u, -p: Są to krótkie opcje dla wszystkich z wyjątkiem obniżenia, którzy nie mają.
  • --safe-upgrade, --full-upgradesą odpowiednikami apt-get„s upgrade/ dist-upgradei aptitude” s safe-upgrade/ full-upgrade. Te nie wymagają parametrów.
  • Istnieje kilka innych operacji, które można znaleźć w instrukcji. Ale są one najczęściej używane przez użytkowników zainteresowanych aptd. Istnieją opcje, które pokrywają się z tym, co apt-key, apt-cache, dpkgzrobić.

apt-getsam nie obsługuje takich metod (czekania na inne instancje apt), więc aptdconjest preferowanym rozwiązaniem dla menedżerów pakietów GUI: USC używa aptdjako zaplecza, tak samo jak Synaptic. Innym rozwiązaniem jest packagekit, ale nie obsługuje funkcji, której szukasz (jeszcze).

Braiam
źródło
1
aptdcon --install /path/to/pgk.debDziała podobnie dpkg -i, chociaż nie znalazłem tego wyraźnie wspomnianego w instrukcji.
whitehat101
Czy mogę tego użyć w skrypcie poinstalacyjnym w pakiecie?
Nelson Teixeira
@NelsonTeixeira dlaczego miałbyś użyć tego w skrypcie ppst-install? Jeśli wykonywana jest instalacja po instalacji, to oczywiście działa apt.
Braiam
Chcę, aby postinstall zainstalował specjalne pakiety, których nie ma w repozytorium. Czy to możliwe ? Umieściłbym je w pakiecie, a następnie skrypt zainstalowałby je po zakończeniu instalacji.
Nelson Teixeira
@NelsonTeixeira ponownie, dlaczego byłoby to konieczne? Skrypty poinstalacyjne działają tylko w przypadku instalacji pakietu. Sugeruję, aby zamiast tego zadać pytanie i wyjaśnić swoją sprawę bardziej szczegółowo.
Braiam
18

Bardzo prostym podejściem byłby skrypt, który czekał, aż zamek nie zostanie otwarty. Nazwijmy to waitforapti wklejmy /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

Więc po prostu biegnij sudo waitforapt && sudo apt-get install whatever. Możesz dodać wyjątki, sudoersaby umożliwić Ci uruchomienie go bez potrzeby podawania hasła (będziesz go potrzebować, apt-getwięc nie będzie to wielki zysk).

Niestety nie powoduje to kolejkowania. Biorąc pod uwagę, że niektóre operacje apt są interaktywne („Czy na pewno chcesz usunąć wszystkie te pakiety ?!”), nie widzę dobrego sposobu na obejście tego ...

Oli
źródło
może -yzałożyć tak dla wszystkich operacji?
Braiam
Dziękuję Ci. Myślę, że mogę go lepiej wykorzystać, jeśli użyję aliasu pomocy.
rɑːdʒɑ
3
Nie -yjest to jednak pożądane.
Oli
1
Nie sądzę chcesz zawinąć sudo fuserw [[ $(...) ]]. Zwraca zerowy kod wyjścia podczas dostępu do pliku, więc powinno to wystarczyć.
kiri
4
Znalazłem następujące rozwiązanie, które jest bardziej kompletne, ponieważ podczas pracy z apt-get występuje kilka blokad: 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

Możesz użyć techniki odpytywania:

$ time (while ps -opid= -C apt-get > /dev/null; do sleep 1; done); \
  apt-get -y install some-other-package
malthe
źródło
lepiej użyćinotify
ctrl-alt-delor
3

Stworzyłem skrypt, który to robi:

#!/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

Zapisz powyższe w /usr/local/sbin/apt-get. apt-getbędzie wtedy czekać, jeśli inna instancja już działa.

Możesz też zapisać jako /usr/local/sbin/apt-waitprzykładowe użycie:

apt-wait && aptitude

który będzie działał aptitudepo wyjściu bieżącego procesu z blokadą.

Przykładowy przebieg:

  1. Najpierw apt-geturuchamiane jest polecenie, na przykład:

    $ sudo apt-get remove some_package
    
  2. Następnie w innym terminalu uruchamiane jest inne polecenie:

    $ sudo apt-get install some_other_package
    

    Będzie czekać na zakończenie pierwszego polecenia, a następnie uruchomi się. Wyjście podczas oczekiwania:

    [/] Waiting for other package managers to finish...
          28223 : /usr/bin/apt-get remove some_package
    
kiri
źródło
1
lepiej użyćinotify
ctrl-alt-delor
3

Niestety fuser nie robi wiele dla ciebie, gdy pracujesz w różnych nieuprzywilejowanych kontenerach przestrzeni nazw, takich jak lxc.

Ponadto aptdcon nie jest domyślnie instalowany (przynajmniej 18.04) i ustawia zadania w tle w kolejce, co powoduje utratę serializacji. Nie jest to nie do pokonania, ale oznacza to, że twoja automatyzacja musi mieć jakiś sposób, aby uniknąć błędów kłaczków w apt podczas instalacji aptdcon, i będziesz musiał mieć jakieś pętle oczekiwania na wszystko, co potrzebujesz do serializacji po zainstalowaniu pakietów przez aptdcon chyba że istnieje już jakaś flaga.

To, co działa, to stado. Powinno to również działać w systemie plików NFS itp., Ponieważ korzysta on z blokowania systemu plików w taki sam sposób, jak apt, tylko z parametrem -w sekund będzie czekać na blokadę zamiast zgłaszać błąd.

Więc zgodnie z modelem otoki, dodaj to jako apt-get w / usr / local / bin / i udostępnij.

Ma to również tę zaletę, że ogranicza IO, ponieważ nie pozwala na równoległość apt, dzięki czemu możesz pozwolić cronowi na uruchamianie aktualizacji o północy wszędzie bez przyspieszania dysku.

#!/bin/bash
exec /usr/bin/flock -w 900 -F --verbose /var/cache/apt/archives/lock /usr/bin/apt-get $@  

Bardzo ładną i prostą prośbą o funkcję dla apt-get byłaby flaga -w, aby przełączyć się na blokowanie / blokowanie oczekiwania.

Raymond Ferguson
źródło
apt używa fcntl, a nie flock, więc to nie zadziała. askubuntu.com/questions/1077215/…
Andy
Działa to doskonale i jest lepszą opcją niż używanie, fuserjak pokazano w wielu odpowiedziach, ponieważ fusernadal jest podatny na warunki wyścigowe między oglądaniem zamka a procesem docelowym chwytania zamka ponownie. Z flockblokadą jest pobierany, a następnie przekazywany do procesu docelowego, więc nie pozostawia czasu na utratę blokady w międzyczasie.
jrudolph
1

One-liner oparty na odpowiedzi Oli :

while sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do sleep 1; done
Menasheh
źródło