Rzetelnie sprawdź, czy pakiet jest zainstalowany, czy nie

20

Mam prosty wymóg. Chcę zdefiniować kilka zmiennych, które będą odpowiadały dowolnej liczbie podanych pakietów, które chcę zainstalować za pomocą skryptu powłoki.

Przykładowy kod poniżej:

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

Wszystko trochę działa, ale logika wydaje się wadliwa, ponieważ nie niezawodne instalowanie pakietów, których chcę. Mówi albo, że zostały już zainstalowane, albo próbuje zainstalować pakiety, które zostały już zainstalowane wcześniej.

Próbowałem również z command -vlub następujące:

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

A nawet z flagami -ni, -zaby sprawdzić, czy zwrócony ciąg był pusty. Jestem prawie pewien, że brakuje mi tutaj rozsądku.

Czy masz pojęcie, co mogę zrobić, aby upewnić się, że pakiet jest rzeczywiście zainstalowany, czy nie?

Dzięki!

vanz
źródło
Co za szkoda, jeśli wołasz także apt-get installo zainstalowane pakiety? Możesz po prostu zadzwonić apt-get install $MISC $WEB.
jarno

Odpowiedzi:

15

Zasadniczo wystarczy zastąpić ifwarunek

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

Nie jest możliwe użycie dpkg-query, ponieważ zwraca wartość true również dla pakietów usuniętych, ale nie wyczyszczonych.

Sugeruję również, aby sprawdzić kod wyjścia apt-getprzed wysłaniem pomyślnego komunikatu:

if apt-get -qq install $pkg; then
    echo "Successfully installed $pkg"
else
    echo "Error installing $pkg"
fi
enzotib
źródło
Co ma &>zrobić?
Taymon
@Taymon: przekieruj stdin i stderr do podanego pliku ( /dev/nullw tym przypadku), ponieważ nie potrzebujemy danych wyjściowych, tylko kod wyjścia. Działa tylko w bash(musi być pierwszy wiersz skryptu #!/bin/bash), w przeciwnym razie użyj >/dev/null 2>&1.
enzotib
@Taymon: Zmieniłem logikę, ponieważ znalazłem błąd w poprzednim rozwiązaniu.
enzotib
Uwaga: jeśli używasz bash i ustawiono opcję pipefail, grep -q może wygenerować Heisenbugs. Zasadniczo, grep kończy działanie, zanim dpkg zakończy pisanie (w takim przypadku chcesz mieć status wyjścia 0), więc dpkg nie zapisuje do potoku (który zamiast tego generuje stan wyjścia inny niż 0). Albo upewnij się, że pipefail nie jest ustawiony, albo porzuć (prawdopodobnie niewielki) wzrost wydajności opcji „-q”.
Ron Burk
2

Możesz to przetestować poprzez dpkg-query:

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

Pamiętaj, że * i? są symbolami wieloznacznymi, jeśli występują w $ pkg. Wydaje mi się, że dpkg-query może wypisać „zainstalowany ponownie wymagany” zamiast „ok zainstalowany”, jeśli pakiet jest uszkodzony i wymaga ponownej instalacji za pomocą polecenia, apt-get install --reinstallktórego można również użyć do zainstalowania nowych pakietów.

jarno
źródło
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
Pan Linux
źródło