Wie lässt man einen Paketmanager warten, wenn eine andere Instanz von APT ausgeführt wird?

50

Ich habe viele Programme wie Update Manager und Synaptic Package Manager gesehen, die warten, bis ein anderes Programm das /var/lib/dpkg/lockund verwendet und gesperrt ist. Wie können wir das über das Terminal tun? Ich habe apt-getdas Handbuch gesehen, aber nichts Nützliches gefunden.

Piyush
quelle
Nun, Sie können mehrere apt-get-Befehle ausführen. Like sudo apt-get install packagename && sudo apt-get updateund sie werden automatisch nacheinander passieren.
Alvar
1
Tut das nicht das sudo apt-get install packagename1 packagename2 packagename3 :?
Rinzwind
(Siehe unix.stackexchange.com/questions/463498/…, wenn Sie in dem speziellen Fall sind, in dem Sie darauf warten möchten, dass die Startzeit unter Ubuntu 18.04 oder höher endet. )
Anon,

Antworten:

35

Sie können den aptdconBefehl verwendenManpage-Symbol , um Paketmanager-Tasks in die Warteschlange zu stellen, indem Sie mit aptdaemon kommunizieren, anstatt apt-get direkt zu verwenden.

Im Grunde können Sie einfach etwas tun sudo aptdcon --install chromium-browseroder was auch immer, und während dieser Befehl ausgeführt wird, können Sie ihn erneut ausführen, aber verschiedene Pakete installieren, und apt-daemon wird sie einfach in die Warteschlange stellen, anstatt einen Fehler zu machen.

Dies ist besonders nützlich, wenn Sie ein langes Upgrade oder etwas anderes durchführen und weiterhin Pakete installieren möchten oder wenn Sie gemeinsam Skripte erstellen und sicherstellen möchten, dass die Installation zuverlässiger ist.

Jorge Castro
quelle
4
Kann aptdconso ausgeführt werden, dass Eingabeaufforderungen akzeptiert werden apt-get -y?
Nokia
4
yes | aptdcon --hide-terminal --install "package"Hide Terminal wird benötigt, da sonst yesProbleme mit der Verrohrung auftreten .
Whitehat101
1
Das Problem bei dieser Antwort ist, dass eine Installation erforderlich ist aptdcon. Ich arbeite an einem Bootstrap-Skript, das die Ersteinrichtung eines VPS durchführt, wobei ein Hintergrundprozess auch eine Ersteinrichtung vornimmt. Ich kann erst installieren, aptdconwenn ich das Schloss umgehen kann.
Fake Name
2
@FakeName für die anfängliche Serverkonfiguration möchten Sie wahrscheinlich cloud-init verwenden: cloudinit.readthedocs.io/en/latest
Jorge Castro
1
In welchem ​​Paket ist aptdcon?
Strg-Alt-Delor
45

Sie können apt-getlernen, zu warten, wenn ein anderer Software-Manager ausgeführt wird. Ähnliches gilt für das Verhalten aus der nächsten Bildschirmdarstellung:

Bildbeschreibung hier eingeben

Wie habe ich es gemacht?

Ich erstelle ein neues Skript namens apt-get(wrapper for apt-get) im /usr/local/sbinVerzeichnis mit dem folgenden Bash-Code:

#!/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 "$@"

Vergiss nicht, es ausführbar zu machen:

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

Überprüfen Sie vor dem Testen, ob alles in Ordnung ist. Die Ausgabe des which apt-getBefehls sollte jetzt sein /usr/local/sbin/apt-get. Der Grund ist: Standardmäßig steht das /usr/local/sbinVerzeichnis vor dem /usr/binVerzeichnis in user oder root PATH.

Radu Rădeanu
quelle
Das ist wirklich ein direkter Treffer für meine Frage. danke :)
rɑːdʒɑ
2
Wie verwaltet Ihr Skript gestapelte Instanzen von apt-get? Wie, bevor es zu Ende ist, starte ich noch 5 apt-get?
Braiam
@Braiam Mit freundlichen Grüßen, ich weiß es nicht; Ich bin kein guter Tester. Hast du es getestet? Wenn Probleme auftreten, kann das Skript verbessert werden, indem beim Start einer neuen Instanz des Skripts eine neue Sperre mit Zeitstempel erstellt wird (nur ein Beispiel - es gibt auch viele andere Möglichkeiten).
Radu Rădeanu
Beeindruckend! beredt. funktioniert wie ein Zauber mit allem, was ich bisher drauf geworfen habe! Zwei Daumen hoch ... dies sollte nur ein Teil des Pakets sein: D
Eric
2
Das ist perfekt! Ich hatte ein Problem mit AWS cloudinit, um Pakete auf einem neuen Server zu installieren, aber Ubuntu führt aptbeim Booten einige Aufgaben aus, sodass mein dpkgBefehl fehlgeschlagen ist, weil dpkg db gesperrt ist. Ich habe diesen Einzeiler in meine cloudinit-Benutzerdaten eingefügt: while fuser /var/lib/dpkg/lock >/dev/null 2>&1; do sleep 1; done; dpkg -i package.debund er funktioniert hervorragend.
Volodymyr Smotesko
20

Abgesehen von dem Offensichtlichen &&, können Sie suchen aptdcon. Dieses Tool kann andere Instanzen von apt erkennen und warten, bis sie beendet sind:

sudo aptdcon - sicheres Upgrade
[/] 11% Warten, bis andere Software-Manager das Warten auf Eignung beendet haben

(Ich renne aptitude woanders hin)

Der Vorteil dieses Tools besteht darin, dass Sie mehrere Aktionen nacheinander speichern können, ohne sich Gedanken darüber machen zu müssen, was Sie als Nächstes tun werden. aptdconist ideal für unbeaufsichtigte Skripte und die GUI-Installation, da Sie das Tool im Hintergrund ausführen lassen können, um Ihr Frontend nicht zu blockieren.

Die von unterstützten Operationen aptdconsind:

  • --refresh, -c: Dies ist das Äquivalent zu apt-get update. Es aktualisiert Ihre Paketliste.
  • --install, --remove, --upgrade, --purge, --downgrade. Jeder von ihnen tut, was sein Name sagt. Der Name des Pakets (der Pakete) ist obligatorisch. -i, -r, -u, -pDas sind die Short - Optionen für alle außer Herabstufung, der keinen hat.
  • --safe-upgrade, --full-upgradesind die Gegenstücke zu apt-get's upgrade/ dist-upgradeund aptitude' s safe-upgrade/ full-upgrade. Diese benötigen keine Parameter.
  • Es gibt mehrere andere Vorgänge, die im Handbuch aufgeführt sind. Diese werden jedoch am häufigsten von Benutzern verwendet, die an interessiert sind aptd. Es gibt Optionen , die mit überlappen , was apt-key, apt-cache, dpkgzu tun.

apt-getselbst unterstützt solche Methoden nicht (um auf andere Instanzen von apt zu warten), daher aptdconist dies die bevorzugte Lösung für die GUI-Paketmanager: USC verwendet aptddasselbe Back-End wie Synaptic. Eine andere Lösung ist packagekit, aber sie unterstützt die gesuchte Funktion (noch) nicht.

Braiam
quelle
1
aptdcon --install /path/to/pgk.debFunktioniert so dpkg -i, obwohl ich das nicht explizit im Handbuch finden konnte.
Whitehat101
Kann ich dieses Skript nach der Installation in einem Paket verwenden?
Nelson Teixeira
@ NelsonTeixeira, warum sollten Sie dies im ppst-install-Skript verwenden? Wenn die Nachinstallation ausgeführt wird, läuft offensichtlich apt.
Braiam
Ich möchte nach der Installation einige spezielle Pakete installieren lassen, die sich nicht im Repository befinden. Ist das möglich ? Ich würde sie in Paket einschließen und dann würde das Skript sie nach Abschluss der Installation installieren.
Nelson Teixeira
@ NelsonTeixeira nochmal, warum wäre es nötig? Die Post-Install-Skripte werden nur ausgeführt, wenn eine Paketinstallation vorliegt. Ich schlage vor, dass Sie stattdessen eine Frage stellen und Ihren Fall genauer erläutern.
Braiam
18

Ein sehr einfacher Ansatz wäre ein Skript, das darauf wartet, dass das Schloss nicht geöffnet wird. Nennen wir es waitforaptund stecken es in /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

Dann renn einfach sudo waitforapt && sudo apt-get install whatever. Sie können Ausnahmen hinzufügen sudoers, damit Sie es ausführen können, ohne ein Kennwort zu benötigen (Sie benötigen es für die, apt-getso dass es kein großer Gewinn ist).

Leider steht das nicht in der Warteschlange. Da einige Operationen von apt interaktiv sind ("Sind Sie sicher, dass Sie alle diese Pakete entfernen möchten ?!"), sehe ich keinen guten Weg, dies zu umgehen ...

Oli
quelle
vielleicht -yja für alle operationen anzunehmen?
Braiam
Danke. Ich denke, ich kann es besser nutzen, wenn ich Alias-Hilfe benutze.
Dienstag,
3
In nicht sicher -yist jedoch wünschenswert.
Oli
1
Ich glaube nicht , Sie wickeln wollen sudo fuserin [[ $(...) ]]. Beim Zugriff auf die Datei wird ein Exit-Code von Null zurückgegeben, sodass dies ausreichen sollte.
kiri
4
Ich fand die folgende Lösung vollständiger, da es bei der Arbeit mit apt-get mehrere Sperren gibt: 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

Sie können eine Abfragetechnik verwenden:

$ time (while ps -opid= -C apt-get > /dev/null; do sleep 1; done); \
  apt-get -y install some-other-package
malthe
quelle
besser zu bedieneninotify
Strg-Alt-Delor
3

Ich habe ein Skript erstellt, das dies tut:

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

Speichern Sie die oben genannten in /usr/local/sbin/apt-get. apt-getWartet dann, ob bereits eine andere Instanz ausgeführt wird.

Speichern Sie es alternativ als /usr/local/sbin/apt-waitBeispiel:

apt-wait && aptitude

Dies wird ausgeführt, aptitudenachdem der aktuelle Prozess, der die Sperre hält, beendet wurde.

Beispiellauf:

  1. Zuerst wird ein apt-getBefehl ausgeführt, zum Beispiel:

    $ sudo apt-get remove some_package
    
  2. Dann wird in einem anderen Terminal ein anderer Befehl ausgeführt:

    $ sudo apt-get install some_other_package
    

    Es wird darauf gewartet, dass der erste Befehl beendet und dann ausgeführt wird. Ausgabe während des Wartens:

    [/] Waiting for other package managers to finish...
          28223 : /usr/bin/apt-get remove some_package
    
kiri
quelle
1
besser zu bedieneninotify
Strg-Alt-Delor
3

Leider leistet fuser nicht viel für Sie, wenn Sie in verschiedenen nicht privilegierten Namespace-Containern wie lxc arbeiten.

Außerdem ist aptdcon nicht standardmäßig installiert (mindestens am 18.04.) Und hinterlässt Ihre Aufgabe in einer Warteschlange, sodass Sie die Serialisierung verlieren. Dies ist nicht unüberwindbar, aber es bedeutet, dass Ihre Automatisierung bei der Installation von aptdcon einige Möglichkeiten haben muss, um Flockfehler in apt zu vermeiden, und dass Sie eine Art Warteschleife für alles benötigen, was Sie nach der Installation von Paketen über aptdcon serialisieren müssen es sei denn, es gibt bereits eine Art Flagge dafür.

Was funktioniert, ist Herde. Dies sollte auch über NFS usw. funktionieren, da die Dateisystemsperrung auf die gleiche Weise wie bei apt verwendet wird. Nur mit dem Parameter -w seconds wird auf Ihre Sperre gewartet, anstatt einen Fehler auszulösen.

Fügen Sie dies dem Wrapper-Modell folgend als apt-get in / usr / local / bin / hinzu und geben Sie es frei.

Dies hat auch den Vorteil, dass die Anzahl der E / A-Vorgänge begrenzt wird, da bei apt keine Parallelität zugelassen wird, sodass Sie Aktualisierungen von cron überall um Mitternacht auslösen können, ohne die Festplatte zu beschädigen.

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

Eine sehr nette und einfache Feature-Anfrage für apt-get wäre ein -w-Flag, um zu einer Blockierungs- / Wartesperre zu wechseln.

Raymond Ferguson
quelle
apt benutzt fcntl, nicht flock, also funktioniert das nicht. askubuntu.com/questions/1077215/…
Andy
Dies funktioniert einwandfrei und ist eine bessere Option als die fuserin vielen Antworten gezeigte, da fuseres immer noch zu Wettlaufsituationen zwischen dem Beobachten der Sperre und dem erneuten Ergreifen der Sperre durch den Zielprozess kommt. Mit flockder Sperre wird erfasst und dann an den Zielprozess übergeben, so dass keine Zeit mehr bleibt, die Sperre in der Zwischenzeit zu verlieren.
Jrudolph
1

Einzeiler basierend auf Olis Antwort :

while sudo fuser /var/{lib/{dpkg,apt/lists},cache/apt/archives}/lock >/dev/null 2>&1; do sleep 1; done
Menasheh
quelle