Перевірте, чи встановлений пакет apt-get, а потім встановіть його, якщо його немає в Linux


223

Я працюю над системою 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
Імена команд не завжди відображають ім'я пакету, до якого вони належать. Яка ти більша мета? Чому б вам просто не спробувати встановити його, а в гіршому випадку цього не вийде, оскільки він уже встановлений.
viam0Zah

8
На щастя, apt-get install є ідентичним, тому безпечно просто запустити його і не турбуватися, встановлений він чи ні.
Девід Баукум

@ Коментар DavidBaucum повинен бути відповіддю, який отримав би найбільше голосів.
Nirmal

@ Nirmal, відповідь зроблена.
Девід Баукум

1
Пов'язані, ви повинні використовувати command -v <command>; ні which <command>. Також див. Перевірте, чи існує програма зі сценарію Bash .
jww

Відповіді:


314

Щоб перевірити, чи packagenameвстановлено, введіть:

dpkg -s <packagename>

Ви також можете використовувати, dpkg-queryякий має чіткіший вихід для ваших цілей, і приймає дикі карти теж.

dpkg-query -l <packagename>

Щоб знайти, яким пакетом належить command, спробуйте:

dpkg -S `which <command>`

Докладніші відомості див. У статті Дізнайтеся, чи встановлений пакунок у Linux та шпаргалках dpkg .


31
Якщо ви як людина хочете цього НЕ-програмно, ви можете використовувати цю інформацію як є. Однак ви не можете просто покластися на зворотні коди тут для сценаріїв або вихід / відсутність одного виводу тільки для сценаріїв. Вам доведеться сканувати вихід цих команд, обмежуючи їх корисність для цього питання.
UpAndAdam

4
Як не дивно, я нещодавно виявив, що dpkg-запит, що використовується для повернення 1 у відсутньому пакеті, тепер (Ubuntu 12.04) повертає 0, викликаючи всілякі проблеми в моєму сценарії налаштування вузла jenkins! dpkg -s повертає 0 на встановлений пакет, а 1 на пакет не встановлено.
Therealstubot

17
Гей, ОП попросили ifвикористовувати. Я також шукаю ifвикористання.
Томаш Зато - Відновіть Моніку

1
@Therealstubot: Я також використовую Ubuntu 12.04 і dpkg -sповертає 1 на відсутніх пакунках і 0 в іншому випадку, як слід. Чим відрізнялися попередні (чи останні) версії?
MestreLion

4
Примітка: dpkg -sповертає нуль, якщо пакет був встановлений, а потім видалений - у такому випадку це Status: deinstall ok config-filesчи подібне, тож це "нормально" - так що для мене це не є безпечним тестом. dpkg-query -lздається, що і в цьому випадку корисний результат не повертається.
захопливий

86

Щоб бути більш чітким, ось трохи скрипту bash, який перевіряє пакет і встановлює його, якщо потрібно. Звичайно, ви можете зробити інші речі, виявивши, що пакет відсутній, наприклад, просто вийти з кодом помилки.

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

Якщо скрипт працює в графічному інтерфейсі (наприклад, це сценарій Nautilus), ви, ймовірно, захочете замінити виклик "sudo" на "gksudo".


5
--force-yesздається поганою ідеєю. Зі сторінки чоловіка: "Це небезпечний варіант, який спричинить продовження apt-get без підказки, якщо він робить щось потенційно шкідливе. Його не слід використовувати, крім випадків, коли в дуже особливих ситуаціях. Використання --force-yes може потенційно зруйнувати вашу систему ! " Використання його в сценарії робить це ще гірше.
зниження активності

68

Цей однолінійний параметр повертає 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 $?
ThorSummoner

@ThorSummoner: хочете пояснити, чому вам краще?
knocte

1
@knocte Я не впевнений, що можна зробити аргументи щодо того, щоб бути об'єктивно кращим. Хоча я впевнений, що однослідовий пост докладної пошти виконає результат результату, який я не хотів би залишати звисаючим у відповіді. Я показую один вкладиш ілюструє отримання (друкування) просто вихідного коду.
ThorSummoner

1
@ThorSummoner Вам не потрібно grep -Pпростий такий регулярний вираз.
tripleee

7
Простіше: if ! dpkg-query -W -f='${Status}' nano | grep "ok installed"; then apt install nano; fi- Не потрібно користуватися grep -c, просто використовуйте статус виходуgrep
Стівен Остерміллер

17

dpkg -s програмне використання з автоматичною установкою

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

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

man dpkg на жаль, не документально підтверджує статус виходу, але я думаю, що на нього слід покладатися досить безпечно:

-s, --status package-name...
    Report status of specified package.

Варто зазначити одне, що працює:

sudo apt remove <package-name>

не обов’язково видаляти всі файли відразу для деяких пакунків (але це стосується інших, не знаю, чому?), а просто позначає пакет для видалення.

У такому стані пакет, як видається, є корисним і тому, що його файли все ще є, але він буде позначений для видалення пізніше.

Наприклад, якщо ви запускаєте:

pkg=certbot

sudo apt install -y "$pkg"
dpkg -s "$pkg"
echo $?

sudo apt remove -y "$pkg"
dpkg -s "$pkg"
echo $?
ls -l /usr/lib/python3/dist-packages/certbot/reporter.py

sudo apt remove --purge certbot
dpkg -s "$pkg"
echo $?
ls -l /usr/lib/python3/dist-packages/certbot/reporter.py

тоді:

  • перші два echo $?вихідні дані 0, лише третій1

  • вихід для першого dpkg -s certbotмістить:

    Status: deinstall ok installed

    а другий говорить:

    Status: deinstall ok config-files

    і він зникає лише після очищення:

    dpkg-query: package 'certbot' is not installed and no information is available
  • файл /etc/logrotate.d/certbotвсе ще присутній в системі після apt remove, але не після --purge.

    Однак файл /usr/lib/python3/dist-packages/certbot/reporter.pyвсе ще присутній навіть після --purge.

Я не розумію чому, але з helloпакетом другий dpkgпісля apt removeпоказує, що він вже видалений без --purge:

dpkg-query: package 'hello' is not installed and no information is available

Документація також дуже неясна, наприклад:

sudo apt dselect-upgrade

не видаляв, certbotколи це було позначено як deinstall, хоча, man apt-getздається, вказує на те, що:

dselect-upgradeвикористовується спільно з традиційною передньою частиною упаковки Debian, dselect (1). dselect-upgrade слідкує за змінами, внесеними dselect (1) у поле Status для доступних пакетів, та виконує дії, необхідні для усвідомлення цього стану (наприклад, видалення старих та встановлення нових пакетів).

Дивитися також:

Тестовано на Ubuntu 19.10.

aptПакет Python

Існує попередньо встановлений пакет Python 3, який називається aptUbuntu 18.04, який відкриває інтерфейс Python apt!

Сценарій, який перевіряє, чи встановлено пакунок, і встановлює його, якщо його немає, можна побачити на: Як встановити пакет за допомогою API python-apt

Ось копія для довідки:

#!/usr/bin/env python
# aptinstall.py

import apt
import sys

pkg_name = "libjs-yui-doc"

cache = apt.cache.Cache()
cache.update()
cache.open()

pkg = cache[pkg_name]
if pkg.is_installed:
    print "{pkg_name} already installed".format(pkg_name=pkg_name)
else:
    pkg.mark_install()

    try:
        cache.commit()
    except Exception, arg:
        print >> sys.stderr, "Sorry, package installation failed [{err}]".format(err=str(arg))

Перевірте, чи PATHзамість цього виконується виконуваний файл

Див.: Як я можу перевірити, чи існує програма зі сценарію Bash?


Циро, ви не можете покладатися на код виходу "dpkg -s". Наприклад, якщо ви "apt встановив" пакет, потім "apt видаліть" його і спробував "dpkg -s ім'я пакета", тоді ви помітите статус: видалити та вийти з коду нуля (як би встановлено). Ви повинні проаналізувати вихідний броу "dpkg -s".
Дмитро Шевкопляс

@DmitryShevkoplyas дякую за доповідь. Я не міг відтворити на Ubuntu 19.10 з: sudo apt install hello; dpkg -s hello; echo $?; sudo apt remove hello; dpkg -s hello; echo $?. Чи можете ви надати додаткову інформацію?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

1
Дійсно - для вашого тестового випадку з пакетом "привіт" "dpkg -s" правильно показує, що пакет не встановлений, і дає очікуваний вихідний код "1". Але спробуйте те ж саме встановити / видалити чек з пакетом "certbot", тоді ви побачите "Статус: видаліть ок-конфігураційні файли" як вихід "dpkg -s" після того, як ваш "apt видалити certbot", і код виходу неправильно показує нам "0". Моє помилкове припущення полягало в тому, що це стосується будь-якого іншого пакету, але, здається, він не для всіх однаковий, що ще гірше і менш передбачуване. Розбирати "dpkg -s" ви повинні (c) Йода :)
Дмитро Шевкопляс

11

Я пропоную це оновлення, оскільки Ubuntu додав "Архів особистих пакетів" (PPA) так само, як відповіли на це питання, і пакети PPA мають інший результат.

  1. Пакет репозиторію Native 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.

Також розміщено на сайті: /superuser/427318/test-if-a-package-is-installed-in-apt/427898


2
Якщо ви встановите та вилучите пакунок, наступним чином будете використовувати пакет dpkg-query; ехо $? також буде 0, якщо пакет не встановлений.
Пол Галлен

8

UpAndAdam написав:

Однак ви не можете просто покластися на коди повернення для сценаріїв

На мій досвід, ви можете покластися на вихідні коди dkpg.

Код повернення dpkg -s дорівнює 0, якщо пакет встановлений, і 1, якщо його немає, тож найпростішим рішенням, яке я знайшов, було:

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

Для мене добре працює ...


11
Після apt-get remove <package>, dpkg -s <package>як і раніше, повертає 0, хоча пакетdeinstalled
ThorSummoner

7

Це, здається, працює досить добре.

$ sudo dpkg-query -l | grep <some_package_name> | wc -l
  • Він або повертається, 0якщо він не встановлений, або деякий номер, > 0якщо він встановлений.

8
grep | wc -lє антипатерном. Щоб перевірити, чи щось існує, потрібно просто grep -q. Щоб насправді підрахувати події (що рідко корисно в такому сценарії), використовуйте grep -c.
tripleee

@tripleee Отже dpkg -s zip | grep -c "Package: zip",? (використовуючи поштовий індекс в якості зразка)
Девід Табернеро М.

@Davdriver Це не зовсім те, що описано вище, але так. У сценарії ви, ймовірно, хочете grep -q 'Package: zip'повернути код виходу, який вказує, чи був знайдений результат, не надрукувавши нічого.
трійка

здається, це добре працює і для невстановлених пакетів
mehmet

4

Я вирішив на основі відповіді Нултія :

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 набагато простіше проаналізувати, ніж більшість інших, оскільки воно не включає статуси на зразок "видалення". Він також може перевіряти декілька пакетів одночасно, що ви не можете зробити лише з кодами помилок.

Пояснення / приклад:

$ 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оскільки, як згадується в коментарях, це може несподівано оновити пакети, які ви не планували; не дуже гарна ідея для автоматизованих процесів, які, як очікується, будуть стабільними.


Мені подобається це рішення. Стислі і тести для декількох пакетів одночасно. Крім того, ви можете зробити додаткову перевірку на щось таке просто, як[[ ! -z $MISSING ]] && sudo apt-get install $MISSING
Шенк

3

Я виявив, що всі рішення вище можуть призвести до помилкового позитиву, якщо пакет встановлений, а потім видалений, але інсталяційний пакет залишається в системі.

Для копіювання: Встановіть пакет apt-get install curl
Видалити пакетapt-get remove curl

Тепер тест вище відповідей.

Наступна команда, здається, вирішує цю умову:
dpkg-query -W -f='${Status}\n' curl | head -n1 | awk '{print $3;}' | grep -q '^installed$'

Це призведе до остаточного встановлений або не встановлено


Не зовсім сумно - інші можливі результати в цьому випадку config-files- тому я думаю, що | grep -q "installed"для отримання статусу функціонального коду виходу дійсно потрібен фінал .
захопливий

зробити це| grep -q '^installed$'
захоплено

3

Здається, що сьогодні apt-getє варіант, --no-upgradeякий просто робить те, що хоче ОП:

--no-upgradeНе оновлюйте пакети. Якщо використовуватись разом із встановленням, без оновлення перешкоджатиме оновлення перелічених пакетів, якщо вони вже встановлені.

Manpage від https://linux.die.net/man/8/apt-get

Тому ви можете використовувати

apt-get install --no-upgrade package

і packageбуде встановлено лише якщо його немає.



2

Це зробить це. apt-get installє безсильним.

sudo apt-get install command

5
Існують сценарії, в яких виконувати apt-get installнад пакетом небажано, коли пакет уже встановлений, навіть якщо сама команда є ідентичною. У моєму випадку я встановлюю пакет у віддаленій системі з необробленим модулем Ansible, який повідомляє про систему як про щоразу змінену, якщо я запускаю apt-get installбез розбору. Умовно вирішує цю проблему.
JBentley

1
@JBentley Це хороший момент. Пакети, встановлені як частина залежності, будуть позначені як встановлені вручну, а потім не будуть видалені, коли її залежність буде видалена, якщо ви підхопите її встановити.
Девід Баукум

2

Використання:

apt-cache policy <package_name>

Якщо він не встановлений, він покаже:

Installed: none

Інакше це покаже:

Installed: version

1

Ця функція вже існує в command-not-foundпакеті Ubuntu та Debian .


15
matt @ matt-ubuntu: ~ $ command-not-found команда-not-found: команда не знайдена ... lol.
Метт Флетчер

1
command-not-foundє інтерактивним помічником, а не інструментом для забезпечення ваших залежностей. Звичайно, правильним способом декларування залежностей є упаковка свого програмного забезпечення в пакет Debian та належне заповнення Depends:декларації у debian/controlфайлі пакета .
трійка

1
apt list [packagename]

Здається, це найпростіший спосіб зробити це за межами dpkg та старих інструментів *


Це добре для ручної перевірки, але воно видає попередження про те, що apt не призначений для сценаріїв - на відміну від інструментів apt *.
Hontvári Levente


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

Я перенаправляю вихід помилки на null, оскільки apt застерігає від використання свого "нестабільного кліпу". Я підозрюю, що список списку стабільний, тому я думаю, що нормально відкинути це попередження. -Qq робить сприятливим супер тихий.


1
це не спрацює належним чином, якщо щось можна "
оновити

@PawelBarcik хороший момент. Я оновив відповідь, щоб вирішити цю ситуацію.
carlin.scott

0

Ця команда є найбільш пам'ятною:

dpkg --get-selections <package-name>

Якщо він встановлений, він друкує:

<ім'я пакета> встановити

Інакше він друкує

Не знайдено жодних пакетів, що відповідають <name-pack-name>.

Це було перевірено на Ubuntu 12.04.1 (Precision Pangolin).


4
dpkg --get-selections <package-name>не встановлює вихідний код ненульовим, коли пакет не знайдено.
Лукас

0

Багато речей було сказано, але для мене найпростіший спосіб:

dpkg -l | grep packagename

0

На Bash:

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

Зауважте, що ви можете мати рядок з декількома пакетами в PKG.


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
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.