Проверьте, установлен ли пакет apt-get, а затем установите его, если его нет в Linux?

186

Я работаю над системой Ubuntu, и в настоящее время это то, что я делаю:

if ! which command > /dev/null; then
   echo -e "Command not found! Install? (y/n) \c"
   read
   if "$REPLY" = "y"; then
      sudo apt-get install command
   fi
fi

Это то, что большинство людей будет делать? Или есть более элегантное решение?

  • 7
    Имена команд не всегда отражают имя пакета, к которому они принадлежат. Какова ваша большая цель? Почему бы вам просто не попробовать установить его, а в худшем случае - нет, поскольку он уже установлен.
  • 8
    К счастью, apt-get install идемпотентен, поэтому его можно просто запустить и не беспокоиться о том, установлен он или нет.
Показать ещё 5 комментариев
Теги:
apt-get

21 ответ

273
Лучший ответ

Чтобы проверить, установлен ли packagename, введите:

dpkg -s <packagename>

Вы также можете использовать dpkg-query, который имеет более аккуратный вывод для вашей цели, и принимает также дикие карты.

dpkg-query -l <packagename>

Чтобы узнать, какой пакет принадлежит command, попробуйте:

dpkg -S `which <command>`

Для получения дополнительной информации см. статью Узнайте, установлен ли пакет в Linux и dpkg cheat sheet.

  • 27
    Если вы как личность хотите этого НЕ программно, вы можете использовать эту информацию в том виде, в каком она есть. Однако вы не можете просто полагаться на коды возврата здесь для сценариев или только на вывод / отсутствие вывода для сценариев. Вам придется сканировать вывод этих команд, ограничивая их полезность для этого вопроса.
  • 4
    Как ни странно, я недавно обнаружил, что dpkg-query раньше возвращал 1 для отсутствующего пакета, теперь (Ubuntu 12.04) возвращает 0, вызывая всевозможные проблемы в моем скрипте установки узла сборки jenkins! dpkg -s возвращает 0 для установленного пакета и 1 для не установленного.
Показать ещё 7 комментариев
73

Чтобы быть немного более явным, вот немного bash script, который проверяет наличие пакета и устанавливает его, если требуется. Конечно, вы можете сделать другие вещи, обнаружив, что пакет отсутствует, например, просто выходить с кодом ошибки.

PKG_OK=$(dpkg-query -W --showformat='${Status}\n' the.package.name|grep "install ok installed")
echo Checking for somelib: $PKG_OK
if [ "" == "$PKG_OK" ]; then
  echo "No somelib. Setting up somelib."
  sudo apt-get --force-yes --yes install the.package.name
fi

Если script работает внутри графического интерфейса (например, это Nautilus script), вы, вероятно, захотите заменить вызов 'sudo' на "gksudo".

  • 1
    --force-yes кажется плохой идеей. Со страницы man: «Это опасный параметр, который заставляет apt-get продолжать работу без запроса, если он делает что-то потенциально опасное. Его не следует использовать, за исключением очень особых ситуаций. Использование --force-yes может потенциально разрушить вашу систему !» Использование его в сценарии делает его еще хуже.
58

Этот однострочный файл возвращает 1 (установлен) или 0 (не установлен) для пакета nano.

$(dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed")

даже если пакет не существует/недоступен.

В приведенном ниже примере устанавливается пакет nano, если он не установлен.

if [ $(dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed") -eq 0 ];
then
  apt-get install nano;
fi
  • 4
    Мой вариант: dpkg-query -W -f='${Status}' MYPACKAGE | grep -q -P '^install ok installed$'; echo $?
  • 0
    @ThorSummoner: хотите объяснить, почему ваш лучше?
Показать ещё 5 комментариев
11

Я предлагаю это обновление, так как Ubuntu добавил свой "Архив личных пакетов" (PPA), как только на этот вопрос был дан ответ, и пакеты PPA имеют другой результат.

  1. Собственный пакет репозитория Debian не установлен:

    ~$ dpkg-query -l apache-perl
    ~$ echo $?
    1
    
  2. Пакет PPA зарегистрирован на хосте и установлен:

    ~$ dpkg-query -l libreoffice
    ~$ echo $?
    0
    
  3. Пакет PPA зарегистрирован на хосте, но не установлен:

    ~$ dpkg-query -l domy-ce
    ~$ echo $?
    0
    ~$ sudo apt-get remove domy-ce
    [sudo] password for user: 
    Reading package lists... Done
    Building dependency tree       
    Reading state information... Done
    Package domy-ce is not installed, so not removed
    0 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
    

Также размещено по адресу: https://superuser.com/questions/427318/test-if-a-package-is-installed-in-apt/427898

  • 1
    Если вы устанавливаете и удаляете пакет, далее вы используете пакет dpkg-query; echo $? также будет 0, если пакет не установлен.
7

UpAndAdam писал (а):

Однако вы не можете просто полагаться на коды возврата здесь для сценариев

В моем опыте вы можете полагаться на коды выхода dkpg.

Код возврата dpkg -s 0, если пакет установлен и 1, если это не так, поэтому самым простым решением я нашел:

dpkg -s <pkg-name> 2>/dev/null >/dev/null || sudo apt-get -y install <pkg-name>

Прекрасно работает для меня...

  • 10
    После apt-get remove <package> dpkg -s <package> прежнему возвращает 0, даже если пакет deinstalled
6

Это, похоже, работает очень хорошо.

$ sudo dpkg-query -l | grep <some_package_name> | wc -l
  • Он либо возвращает 0, если не установлен, либо некоторое число > 0, если установлено.
  • 7
    grep | wc -l - это антипаттерн. Чтобы проверить, существует ли что-то, вам нужно просто grep -q . Для фактического подсчета вхождений (что редко бывает полезно в такого рода сценариях) используйте grep -c .
  • 0
    @tripleee Итак, dpkg -s zip | grep -c "Package: zip" ? (используя zip как образец пакета)
Показать ещё 2 комментария
3

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

Повторить: Установить пакет apt-get install curl
Удалить пакет apt-get remove curl

Теперь проверьте выше ответы.

Кажется, что следующая команда разрешает это условие:
dpkg-query -W -f='${Status}\n' curl | head -n1 | awk '{print $3;}' | grep -q '^installed$'

Это приведет к окончательному установлен или не установлен

  • 0
    не совсем, к сожалению - другие возможные результаты в этом случае являются config-files - так что я думаю, что окончательный | grep -q "installed" действительно необходим для получения функционального кода выхода.
  • 0
    сделать это | grep -q '^installed$'
2

dpkg -s программное использование

Мне нравится dpkg -s как он выходит со статусом 1 если какой-либо из пакетов не установлен, что упрощает его автоматизацию:

pkgs='qemu-user pandoc'
if ! dpkg -s $pkgs >/dev/null 2>&1; then
  sudo apt-get install $pkgs
fi

Смотрите также:

Проверено на Ubuntu 18.10.

  • 1
    Это отличный фрагмент кода
2

Я остановился на одном из ответов Нулти:

MISSING=$(dpkg --get-selections $PACKAGES 2>&1 | grep -v 'install$' | awk '{ print $6 }')
# Optional check here to skip bothering with apt-get if $MISSING is empty
sudo apt-get install $MISSING

По сути, сообщение об ошибке из dpkg --get-selections гораздо проще проанализировать, чем большинство других, потому что оно не включает такие состояния, как "deinstall". Он также может проверять несколько пакетов одновременно, чего нельзя сделать только с помощью кодов ошибок.

Объяснение/пример:

$ dpkg --get-selections  python3-venv python3-dev screen build-essential jq
dpkg: no packages found matching python3-venv
dpkg: no packages found matching python3-dev
screen                                          install
build-essential                                 install
dpkg: no packages found matching jq

Поэтому grep удаляет установленные пакеты из списка, а awk извлекает имена пакетов из сообщения об ошибке, в результате чего MISSING='python3-venv python3-dev jq', который можно просто вставить в команду установки.

Я не слепо выдаю apt-get install $PACKAGES потому что, как упоминалось в комментариях, это может неожиданно обновить пакеты, которые вы не планировали; не очень хорошая идея для автоматизированных процессов, которые, как ожидается, будут стабильными.

2

Использование:

apt-cache policy <package_name>

Если он не установлен, он покажет:

Installed: none

В противном случае он покажет:

Installed: version
2

Это сделает это. apt-get install является идемпотентным.

sudo apt-get install command
  • 5
    Существуют сценарии, в которых установка apt-get install для пакета нежелательна, если пакет уже установлен, даже если сама команда является идемпотентной. В моем случае я устанавливаю пакет в удаленной системе с необработанным модулем Ansible, который будет сообщать об изменении системы каждый раз, когда я запускаю apt-get install без разбора. Условное решение этой проблемы.
  • 1
    @JBentley Это хороший момент. Пакеты, установленные как часть зависимости, будут помечены как установленные вручную, а затем не будут удалены при удалении зависимости, если вы установили apt-get.
2
$name="rsync"

[ `which $name` ] $$ echo "$name : installed" || sudo apt-get install -y $name
1

У меня было подобное требование при запуске теста локально, а не в докере. По сути, я хотел установить только те файлы .deb, которые не были установлены.

# If there are .deb files in the folder, then install them
if [ 'ls -1 *.deb 2> /dev/null | wc -l' -gt 0 ]; then
  for file in *.deb; do
    # Only install if not already installed (non-zero exit code)
    dpkg -I ${file} | grep Package: | sed -r 's/ Package:\s+(.*)/\1/g' | xargs dpkg -s
    if [ $? != 0 ]; then
        dpkg -i ${file}
    fi;
  done;
else
  err "No .deb files found in '$PWD'"
fi

Я думаю, что единственная проблема, которую я вижу, заключается в том, что он не проверяет номер версии пакета, поэтому, если файл .deb является более новой версией, это не перезапишет установленный в данный момент пакет.

1

Для Ubuntu apt предоставляет достаточно приличный способ сделать это. Ниже приведен пример для Google Chrome:

apt -qq list google-chrome-stable 2>/dev/null | grep -qE "(installed|upgradeable)" || apt-get install google-chrome-stable

Я перенаправляю вывод ошибок на ноль, потому что apt предупреждает против использования своего "нестабильного кли". Я подозреваю, что список пакетов стабилен, поэтому я думаю, что можно выбросить это предупреждение. -qq делает супер тихий.

  • 1
    это не будет работать должным образом, если что-то «обновляемое»
  • 0
    @PawelBarcik хороший момент. Я обновил ответ, чтобы справиться с этой ситуацией.
1
apt list [packagename]

кажется самым простым способом сделать это за пределами dpkg и более старых apt- * tools

  • 0
    Это хорошо для ручной проверки, но выдает предупреждение о том, что apt не предназначен для сценариев - в отличие от инструментов apt- *.
1

Эта функция уже существует в Ubuntu и Debian в пакете command-not-found.

  • 15
    matt @ matt-ubuntu: ~ $ command-not-found команда-not-found: команда не найдена ... смеется.
  • 1
    command-not-found - это интерактивный помощник, а не инструмент, обеспечивающий наличие необходимых зависимостей. Конечно, правильный способ объявить зависимости - это упаковать свое программное обеспечение в пакет Debian и правильно заполнить объявление Depends: в файле debian/control пакета.
0

Я использую следующий способ:

which mySQL 2>&1|tee 1> /dev/null
  if [[ "$?" == 0 ]]; then
                echo -e "\e[42m MySQL already installed. Moving on...\e[0m"
        else
        sudo apt-get install -y mysql-server
                if [[ "$?" == 0 ]]; then
                        echo -e "\e[42mMy SQL installed\e[0m"
                else
                        echo -e "\e[42Installation failed\e[0m"
                fi
        fi
0

В Баш:

PKG="emacs"
dpkg-query -l $PKG > /dev/null || sudo apt install $PKG

Обратите внимание, что в PKG может быть строка с несколькими пакетами.

0

Многое было сказано, но для меня самый простой способ это:

dpkg -l | grep packagename
0
which <command>
if [ $? == 1 ]; then
    <pkg-manager> -y install <command>
fi
0

Эта команда является наиболее запоминающейся:

dpkg --get-selections <package-name>

Если он установлен, он печатает:

< имя-пакетa > установить

В противном случае он печатает

Не найдено пакетов, соответствующих имени < package-name > .

Это было протестировано на Ubuntu 12.04.1 (Precise Pangolin).

  • 4
    dpkg --get-selections <package-name> не устанавливает ненулевой код выхода, если пакет не найден.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню