Überprüfen Sie zuverlässig, ob ein Paket installiert ist oder nicht

20

Ich habe eine einfache Anforderung. Ich möchte mehrere Variablen definieren, die einer beliebigen Anzahl von Paketen entsprechen, die ich über ein Shell-Skript installieren möchte.

Beispielcode unten:

MISC="shutter pidgin"
WEB="apache2 mongodb"

for pkg in $MISC $WEB; do
    if [ "dpkg-query -W $pkg | awk {'print $1'} = """ ]; then
        echo -e "$pkg is already installed"
    else
        apt-get -qq install $pkg
        echo "Successfully installed $pkg"
    fi
done

Alles funktioniert ein bisschen, aber die Logik scheint fehlerhaft zu sein, weil sie die gewünschten Pakete nicht zuverlässig installiert. Entweder heißt es, dass sie bereits installiert wurden, oder es wird versucht, Pakete zu installieren, die bereits zuvor installiert wurden.

Ich habe auch versucht mit command -voder die folgenden:

if [ "dpkg -l | awk {'print $2'} | grep --regexp=^$pkg$ != """ ]; then

Und selbst mit den Flags -nund kann -zman prüfen, ob der zurückgegebene String leer war. Ich bin mir ziemlich sicher, dass mir hier ein guter Sinn fehlt.

Haben Sie eine Idee, was ich tun könnte, um sicherzustellen, dass ein Paket tatsächlich installiert ist oder nicht?

Vielen Dank!

vanz
quelle
Was schadet es, wenn Sie auch apt-get installinstallierte Pakete anfordern? Sie könnten einfach anrufen apt-get install $MISC $WEB.
jarno

Antworten:

15

Im Wesentlichen müssen Sie nur die ifBedingung durch ersetzen

if dpkg --get-selections | grep -q "^$pkg[[:space:]]*install$" >/dev/null; then

Die Verwendung ist nicht möglich dpkg-query, da sie auch für entfernte, aber nicht gelöschte Pakete true zurückgibt.

Ich schlage auch vor, den Exit-Code von zu überprüfen, apt-getbevor die erfolgreiche Nachricht gesendet wird:

if apt-get -qq install $pkg; then
    echo "Successfully installed $pkg"
else
    echo "Error installing $pkg"
fi
Enzotib
quelle
Was macht &>das?
Taymon
@Taymon: Leite sowohl stdin als auch stderr in die angegebene Datei um ( /dev/nullin diesem Fall), da wir nicht die Ausgabe, sondern nur den Exit-Code benötigen. Es funktioniert nur in bash(die erste Zeile des Skripts muss sein #!/bin/bash), ansonsten verwenden >/dev/null 2>&1.
Enzotib
@ Taymon: Ich habe die Logik geändert, weil ich einen Fehler in der vorhergehenden Lösung gefunden habe.
Enzotib
Achtung: Wenn Sie bash verwenden und die Option pipefail gesetzt ist, kann grep -q Heisenbugs erzeugen. Grundsätzlich wird grep beendet, bevor dpkg mit dem Schreiben fertig ist (in diesem Fall möchten Sie einen 0-Beendigungsstatus haben), sodass dpkg nicht in die Pipe schreiben kann (was stattdessen einen Nicht-0-Beendigungsstatus erzeugt). Stellen Sie entweder sicher, dass Pipefail nicht gesetzt ist, oder lassen Sie die (wahrscheinlich winzigen) Effizienzgewinne der Option "-q" außer Kraft.
Ron Burk
2

Sie können es mit dpkg-query testen:

if dpkg-query -W -f'${Status}' "$pkg" 2>/dev/null | grep -q "ok installed"; then

Beachten Sie, dass * und? sind Wildcards, wenn sie in $ pkg erscheinen. Ich vermute, dpkg-query gibt "reinst-required installed" anstelle von "ok installed" aus, wenn das Paket defekt ist und per Befehl neu installiert werden muss. Mit diesem Befehl apt-get install --reinstallkönnen auch neue Pakete installiert werden.

jarno
quelle
0
#to check package is installed or not without distribution dependency
#!/bin/bash
read -p "Package Name: " pkg
which $pkg > /dev/null 2>&1
if [ $? == 0 ]
then
echo "$pkg is already installed. "
else
read -p "$pkg is not installed. Answer yes/no if want installation_ " request
if  [ $request == "yes" ]
then
yum install $pkg
fi
fi
Herr Linux
quelle