Vérifiez si un package apt-get est installé, puis installez-le s'il n'est pas sous Linux

223

Je travaille sur un système Ubuntu et actuellement c'est ce que je fais:

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

Est-ce ce que la plupart des gens feraient? Ou existe-t-il une solution plus élégante?

John Jiang
la source
7
Les noms de commande ne reflètent pas toujours le nom du package auquel ils appartiennent. Quel est votre objectif plus large? Pourquoi n'essayez-vous pas simplement de l'installer, et dans le pire des cas, ce ne sera pas le cas, car il est déjà installé.
viam0Zah
8
Heureusement, l'installation apt-get est idempotente, il est donc sûr de simplement l'exécuter et ne vous inquiétez pas si elle est installée ou non.
David Baucum
@ Le commentaire de DavidBaucum devrait être une réponse qui obtiendrait le plus de votes.
Nirmal
@Nirmal, réponse faite.
David Baucum
1
En relation, vous devez utiliser command -v <command>; non which <command>. Voir également Vérifier si un programme existe à partir d'un script Bash .
2017 à 17h49

Réponses:

314

Pour vérifier si a packagenameété installé, tapez:

dpkg -s <packagename>

Vous pouvez également utiliser dpkg-queryune sortie plus nette pour votre usage et accepter également les caractères génériques.

dpkg-query -l <packagename>

Pour trouver le package auquel appartient le command, essayez:

dpkg -S `which <command>`

Pour plus de détails, consultez l'article Découvrez si le package est installé dans Linux et la feuille de triche dpkg .

viam0Zah
la source
32
Si vous en tant que personne le souhaitez NON par programmation, vous pouvez utiliser ces informations telles quelles. Cependant, vous ne pouvez pas simplement vous fier aux codes de retour ici pour les scripts ou à la sortie / absence de sortie seule pour les scripts. Vous devrez analyser la sortie de ces commandes, ce qui limite leur utilité pour cette question.
UpAndAdam
4
Curieusement, j'ai récemment découvert que dpkg-query utilisé pour renvoyer 1 sur un paquet manquant, maintenant (Ubuntu 12.04) renvoie 0, provoquant toutes sortes de problèmes sur mon script de configuration du noeud de construction jenkins! dpkg -s renvoie 0 sur le package installé et 1 sur le package non installé.
Therealstubot
18
Hé, OP a demandé l' ifutilisation. Je recherche également une ifutilisation.
Tomáš Zato - Rétablir Monica
1
@Therealstubot: J'utilise également Ubuntu 12.04 et dpkg -sretourne 1 sur les paquets manquants et 0 sinon, comme il se doit. Quelle était la différence sur les versions antérieures (ou récentes)?
MestreLion
4
une note: dpkg -sretourne zéro si un paquet a été installé puis supprimé - dans ce cas c'est Status: deinstall ok config-filesou similaire, donc c'est "ok" - donc pour moi, ce n'est pas un test sûr. dpkg-query -lne semble pas non plus retourner un résultat utile dans ce cas.
vif
86

Pour être un peu plus explicite, voici un peu de script bash qui vérifie un paquet et l'installe si nécessaire. Bien sûr, vous pouvez faire d'autres choses en constatant que le package est manquant, comme simplement quitter avec un code d'erreur.

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

Si le script s'exécute dans une interface graphique (par exemple, il s'agit d'un script Nautilus), vous voudrez probablement remplacer l'invocation 'sudo' par une invocation 'gksudo'.

Urhixidur
la source
5
--force-yessemble une mauvaise idée. Depuis la page de manuel: "C'est une option dangereuse qui fera continuer apt-get sans demander si elle fait quelque chose de potentiellement dangereux. Elle ne doit pas être utilisée sauf dans des situations très spéciales. L'utilisation de --force-yes peut potentiellement détruire votre système ! " L'utiliser dans un script ne fait qu'empirer les choses.
réduction de l'activité le
68

Ce one-liner renvoie 1 (installé) ou 0 (non installé) pour le package 'nano'.

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

même si le package n'existe pas / n'est pas disponible.

L'exemple ci-dessous installe le package 'nano' s'il n'est pas installé.

if [ $(dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed") -eq 0 ];
then
  apt-get install nano;
fi
Seb
la source
4
Ma variation à ce sujet:dpkg-query -W -f='${Status}' MYPACKAGE | grep -q -P '^install ok installed$'; echo $?
ThorSummoner
@ThorSummoner: voulez-vous expliquer pourquoi la vôtre est meilleure?
knocte
1
@knocte Je ne suis pas sûr qu'il y ait un argument à faire pour être objectivement meilleur. Bien que je sois convaincu que la ligne unique du message textuel exécutera la sortie du résultat, que je ne voudrais pas laisser pendre dans une réponse. La doublure que je montre illustre l'obtention (l'impression) du code de sortie.
ThorSummoner
1
@ThorSummoner Vous n'avez pas besoin grep -Pd'une simple expression régulière comme ça.
tripleee
7
Plus simple: if ! dpkg-query -W -f='${Status}' nano | grep "ok installed"; then apt install nano; fi- Pas besoin d'utiliser grep -c, utilisez simplement le statut de sortie degrep
Stephen Ostermiller
17

dpkg -s utilisation programmatique avec installation automatique

J'aime dpkg -scar il se termine avec le statut 1si aucun des packages n'est installé, ce qui facilite l'automatisation:

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

man dpkg ne documente malheureusement pas le statut de sortie, mais je pense qu'il devrait être raisonnablement sûr de s'y fier:

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

Une chose à noter est que l'exécution:

sudo apt remove <package-name>

ne supprime pas nécessairement tous les fichiers immédiatement pour certains packages (mais le fait pour d'autres, vous ne savez pas pourquoi?), et marque simplement le package pour la suppression.

Dans cet état, le package semble être encore utilisable, et comme ses fichiers sont toujours présents, mais il est marqué pour suppression plus tard.

Par exemple, si vous exécutez:

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

puis:

  • les deux premières echo $?sorties 0, seule la troisième sort1

  • la sortie du premier dpkg -s certbotcontient:

    Status: deinstall ok installed

    tandis que le second dit:

    Status: deinstall ok config-files

    et il ne disparaît qu'après purge:

    dpkg-query: package 'certbot' is not installed and no information is available
  • le fichier /etc/logrotate.d/certbotest toujours présent dans le système après apt remove, mais pas après --purge.

    Cependant, le fichier /usr/lib/python3/dist-packages/certbot/reporter.pyest toujours présent même après --purge.

Je ne comprends pas pourquoi, mais avec le hellopackage le deuxième dpkgaprès apt removemontre qu'il a déjà été supprimé sans --purge:

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

Les documentations sont également très peu claires, par exemple:

sudo apt dselect-upgrade

n'a pas supprimé certbotquand il a été marqué comme deinstall, même si cela man apt-getsemble indiquer que:

dselect-upgradeest utilisé en conjonction avec le frontal traditionnel de l’emballage Debian, dselect (1). dselect-upgrade suit les modifications apportées par dselect (1) au champ État des packages disponibles et effectue les actions nécessaires pour réaliser cet état (par exemple, la suppression des anciens et l'installation de nouveaux packages).

Voir également:

Testé sur Ubuntu 19.10.

aptPaquet Python

Il existe un package Python 3 préinstallé appelé aptdans Ubuntu 18.04 qui expose une interface apt Python!

Un script qui vérifie si un package est installé et l'installe sinon peut être vu à: Comment installer un package à l'aide de l'API python-apt

Voici une copie pour référence:

#!/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))

Vérifiez si un exécutable est à la PATHplace

Voir: Comment puis-je vérifier si un programme existe à partir d'un script Bash?

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
Ciro, vous ne pouvez pas vous fier au code de sortie "dpkg -s". Par exemple, si vous "avez installé" un paquet, puis "l'avez supprimé" et que vous avez essayé de "dpkg -s nom_package", vous remarquerez le statut: désinstaller et quitter le code zéro (comme s'il était installé). Vous devez analyser la sortie "dpkg -s" bro.
Dmitry Shevkoplyas
@DmitryShevkoplyas merci pour le rapport. Je ne pouvais pas reproduire sur Ubuntu 19.10 avec: sudo apt install hello; dpkg -s hello; echo $?; sudo apt remove hello; dpkg -s hello; echo $?. Pouvez-vous fournir plus de détails?
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
1
en effet - pour votre cas de test avec le paquet "bonjour" "dpkg -s" montre correctement le paquet comme non installé et donne le code de sortie attendu "1". Mais essayez la même vérification instal / remove avec le package "certbot", vous verrez alors "Status: deinstall ok config-files" comme la sortie "dpkg -s" après votre "apt remove certbot" et le code de sortie nous montre incorrectement "0". Ma mauvaise hypothèse était que c'est le cas exact pour tout autre paquet, mais il semble que ce ne soit pas le même pour tous, ce qui est encore pire et moins prévisible. Analyser "dpkg -s" vous devez (c) Yoda :)
Dmitry Shevkoplyas
11

J'offre cette mise à jour depuis qu'Ubuntu a ajouté son "Personal Package Archive" (PPA) juste au moment où cette question a été répondue, et les packages PPA ont un résultat différent.

  1. Paquet de référentiel Debian natif non installé:

    ~$ dpkg-query -l apache-perl
    ~$ echo $?
    1
  2. Package PPA enregistré sur l'hôte et installé:

    ~$ dpkg-query -l libreoffice
    ~$ echo $?
    0
  3. Package PPA enregistré sur l'hôte mais non installé:

    ~$ 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.

Également publié sur: /superuser/427318/test-if-a-package-is-installed-in-apt/427898

tahoar
la source
2
Si vous installez et supprimez un package, vous utilisez ensuite le package dpkg-query; écho $? sera également 0 si le package n'est pas installé.
Pol Hallen
8

UpAndAdam a écrit:

Cependant, vous ne pouvez pas simplement compter sur les codes de retour ici pour les scripts

D'après mon expérience, vous pouvez vous fier aux codes de sortie de dkpg.

Le code de retour de dpkg -s est 0 si le paquet est installé et 1 si ce n'est pas le cas, donc la solution la plus simple que j'ai trouvée était:

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

Fonctionne bien pour moi ...

rocka84
la source
11
Après apt-get remove <package>, dpkg -s <package>renvoie toujours 0, même si le package estdeinstalled
ThorSummoner
7

Cela semble assez bien fonctionner.

$ sudo dpkg-query -l | grep <some_package_name> | wc -l
  • Il retourne 0s'il n'est pas installé ou un certain nombre > 0s'il est installé.
marchand de sable
la source
8
grep | wc -lest un contre-modèle. Pour vérifier si quelque chose existe, vous voulez simplement grep -q. Pour réellement compter les occurrences (ce qui est rarement utile dans ce type de scénario), utilisez grep -c.
tripleee
@tripleee Alors, dpkg -s zip | grep -c "Package: zip" ? (en utilisant zip comme exemple de package)
David Tabernero M.
@Davdriver Ce n'est pas exactement ce que fait ce qui précède, mais oui. Dans un script, vous souhaiterez probablement grep -q 'Package: zip'renvoyer un code de sortie qui indique si le résultat a été trouvé sans imprimer quoi que ce soit.
tripleee
cela semble bien fonctionner aussi pour les paquets désinstallés
mehmet
4

Je me suis installé sur un basé sur la réponse de Nultyi :

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

Fondamentalement, le message d'erreur de dpkg --get-selections est beaucoup plus facile à analyser que la plupart des autres, car il n'inclut pas de statuts tels que "désinstaller". Il peut également vérifier plusieurs packages simultanément, ce que vous ne pouvez pas faire avec seulement des codes d'erreur.

Explication / exemple:

$ 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

Ainsi, grep supprime les packages installés de la liste et awk extrait les noms des packages du message d'erreur, ce MISSING='python3-venv python3-dev jq'qui peut être inséré de manière triviale dans une commande d'installation.

Je ne publie pas aveuglément apt-get install $PACKAGEScar, comme mentionné dans les commentaires, cela peut mettre à niveau de manière inattendue des packages que vous n'aviez pas prévus; pas vraiment une bonne idée pour les processus automatisés qui devraient être stables.

Izkata
la source
J'aime cette solution. Concis et teste plusieurs packages à la fois. En outre, vous pouvez rendre la vérification facultative quelque chose d'aussi simple que[[ ! -z $MISSING ]] && sudo apt-get install $MISSING
Shenk
3

J'ai trouvé que toutes les solutions ci-dessus peuvent produire un faux positif si un package est installé puis supprimé, mais le package d'installation reste sur le système.

Pour répliquer: installer le package apt-get install curl
Supprimer le packageapt-get remove curl

Testez maintenant les réponses ci-dessus.

La commande suivante semble résoudre cette condition:
dpkg-query -W -f='${Status}\n' curl | head -n1 | awk '{print $3;}' | grep -q '^installed$'

Cela se traduira par une installation définitive ou non installée

marque
la source
pas entièrement, malheureusement - d'autres résultats possibles dans ce cas le sont config-files- donc je pense qu'une finale | grep -q "installed"est vraiment nécessaire pour obtenir un code de sortie fonctionnel.
vif
faire que| grep -q '^installed$'
vif
3

Il semble que de nos jours apt-geta une option --no-upgradequi fait juste ce que le PO veut:

--no-upgradeNe mettez pas à niveau les packages. Lorsqu'il est utilisé en conjonction avec l'installation, aucune mise à niveau empêchera les packages répertoriés d'être mis à niveau s'ils sont déjà installés.

Page de manuel de https://linux.die.net/man/8/apt-get

Vous pouvez donc utiliser

apt-get install --no-upgrade package

et packagene sera installé que si ce n'est pas le cas.

Giovanni Mascellani
la source
2

Cela suffira. apt-get installest idempotent.

sudo apt-get install command
David Baucum
la source
5
Il existe des scénarios dans lesquels faire un apt-get installsur un package n'est pas souhaitable lorsque le package est déjà installé, même si la commande elle-même est idempotente. Dans mon cas, j'installe un package sur un système distant avec le module brut d'Ansible, qui signalera le système comme modifié à chaque fois si j'exécute apt-get installsans discernement. Un conditionnel résout ce problème.
JBentley
1
@JBentley C'est un bon point. Les packages installés dans le cadre d'une dépendance seront marqués comme installés manuellement, puis ne seront pas supprimés lorsque leur dépendance sera supprimée si vous l'avez installé apt-get.
David Baucum
2

Utilisation:

apt-cache policy <package_name>

S'il n'est pas installé, il affichera:

Installed: none

Sinon, il affichera:

Installed: version
Mohammed Noureldin
la source
1

Cette fonctionnalité existe déjà dans Ubuntu et Debian, dans le command-not-foundpackage.

camh
la source
15
matt @ matt-ubuntu: ~ $ command-not-found command-not-found: commande introuvable ... lol.
Matt Fletcher
1
command-not-foundest un assistant interactif, pas un outil pour vous assurer que vous disposez des dépendances souhaitées. Bien sûr, la bonne façon de déclarer les dépendances est de mettre votre logiciel dans un paquet Debian et de remplir correctement la Depends:déclaration dans le debian/controlfichier du paquet .
tripleee
1
apt list [packagename]

semble être le moyen le plus simple de le faire en dehors de dpkg et des outils apt- * plus anciens

Erich
la source
C'est bien pour la vérification manuelle, mais il émet un avertissement indiquant que apt n'est pas destiné à l'écriture de scripts - contrairement aux outils apt- *.
Hontvári Levente
1

J'avais une exigence similaire lors de l'exécution de test localement plutôt que dans docker. Fondamentalement, je voulais uniquement installer les fichiers .deb trouvés s'ils n'étaient pas déjà installés.

# 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

Je suppose que le seul problème que je peux voir est qu'il ne vérifie pas le numéro de version du package, donc si le fichier .deb est une version plus récente, cela n'écrasera pas le package actuellement installé.

Craig
la source
1

Pour Ubuntu, apt fournit un moyen assez décent de le faire. Voici un exemple pour Google Chrome:

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

Je redirige la sortie d'erreur vers null car apt met en garde contre l'utilisation de son "cli instable". Je soupçonne que le package de liste est stable, donc je pense que c'est correct de jeter cet avertissement. Le -qq rend apt super silencieux.

carlin.scott
la source
1
cela ne fonctionnera pas correctement si quelque chose est "évolutif"
Pawel Barcik
@PawelBarcik bon point. J'ai mis à jour la réponse pour gérer cette situation.
carlin.scott
0

Cette commande est la plus mémorable:

dpkg --get-selections <package-name>

S'il est installé, il affiche:

<package-name> install

Sinon, il imprime

Aucun package trouvé correspondant à <package-name>.

Cela a été testé sur Ubuntu 12.04.1 (Precise Pangolin).

iNulty
la source
4
dpkg --get-selections <package-name>ne définit pas le code de sortie sur non nul lorsque le package est introuvable.
Lucas
0

Beaucoup de choses ont été dites mais pour moi la manière la plus simple est:

dpkg -l | grep packagename
Liberté
la source
0

Dans Bash:

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

Notez que vous pouvez avoir une chaîne avec plusieurs packages dans PKG.

Daruma
la source
0

J'utilise la manière suivante:

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
Nitish Jadia
la source