Надежно проверьте, установлен ли пакет или нет

20

У меня есть простое требование. Я хочу определить несколько переменных, которые будут соответствовать любому количеству заданных пакетов, которые я хочу установить через скрипт оболочки.

Пример кода ниже:

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

Все вроде работает, но логика кажется ошибочной, потому что она не надежно устанавливает нужные мне пакеты. Он либо говорит, что они уже установлены, либо пытается установить пакеты, которые уже были установлены ранее.

Я также пытался с command -vили следующее:

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

И даже с -nи -zфлажками , чтобы проверить , если возвращаемая строка была пуста. Уверен, мне здесь не хватает здравого смысла.

Есть ли у вас какие-либо идеи, чтобы я мог убедиться, что пакет действительно установлен или нет?

Благодарность!

vanz
источник
Какой вред, если вы также вызываете apt-get installустановленные пакеты? Вы могли бы просто позвонить apt-get install $MISC $WEB.
Ярно

Ответы:

15

По сути, вам нужно только заменить ifусловие на

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

Невозможно использовать dpkg-query, потому что он возвращает true также для пакетов, удаленных, но не очищенных.

Также я предлагаю проверить код выхода apt-getперед тем, как дать успешное сообщение:

if apt-get -qq install $pkg; then
    echo "Successfully installed $pkg"
else
    echo "Error installing $pkg"
fi
enzotib
источник
Что делает &>?
Таймон
@Taymon: перенаправить как stdin, так и stderr в указанный файл ( /dev/nullв данном случае), потому что нам не нужен вывод, только код выхода. Это работает только в bash(первая строка скрипта должна быть #!/bin/bash), иначе используйте >/dev/null 2>&1.
энзотиб
@ Таймон: Я изменил логику, потому что я нашел недостаток в предыдущем решении.
энзотиб,
Осторожно: если используется bash и установлена ​​опция pipefail, то grep -q может генерировать Heisenbugs. По сути, grep завершает работу до того, как dpkg заканчивает запись (в этом случае вы хотите получить состояние выхода 0), поэтому dpkg не может записать в канал (который вместо этого генерирует состояние выхода не равное 0). Либо убедитесь, что pipefail не установлен, либо отмените (возможно, крошечное) повышение эффективности параметра "-q".
Рон Бурк
2

Вы можете проверить это с помощью dpkg-query:

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

Обратите внимание, что * и? являются подстановочными знаками, если они появляются в $ pkg. Я предполагаю, что dpkg-query может вывести «reinst-required required» вместо «ok install», если пакет поврежден и требует переустановки командой, apt-get install --reinstallкоторая также может быть использована для установки новых пакетов.

Ярно
источник
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
Мистер линукс
источник