How can I check if a package is installed and install it if not?
Asked Answered
B

30

303

I'm working on a Ubuntu system and currently this is what I'm doing:

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

Is this what most people would do? Or is there a more elegant solution?

Bladdernose answered 19/8, 2009 at 6:18 Comment(6)
Command names does not always reflect the package name they are belong to. What is you're larger goal? Why don't you simply try to install it, and worst case it won't, since it's already installed.Themis
Fortunately, apt-get install is idempotent, so it is safe to just run it and not worry about if it is installed or not.Width
Related, you should use command -v <command>; not which <command>. Also see Check if a program exists from a Bash script.Erdrich
@DavidBaucum Not quite; running install on an already-installed package will upgrade it if it's out of date. Usually desirable to keep up-to-date for security issues, but could be surprising if stability is desired.Vaucluse
Also notable: it takes far longer to run an install on an existing package vs check if it is installed by, for example, checking for an entry against a list of installed packages. Like, orders of magnitude longer. It's not a practical solution.Jotter
@DavidBaucum: manually apt installing an already installed package will also mark it as manually installed, a very undesired side-effect if that package was previously set as automatically installed.Edgy
T
370

To check if packagename was installed, type:

dpkg -s <packagename>

You can also use dpkg-query that has a neater output for your purpose, and accepts wild cards, too.

dpkg-query -l <packagename>

To find what package owns the command, try:

dpkg -S `which <command>`

For further details, see article Find out if package is installed in Linux and dpkg cheat sheet.

Themis answered 19/8, 2009 at 6:27 Comment(9)
If you as a person want this NON-programmatically you can use this information as it stands. However you can't simply rely on return codes here for scripting or the output/lack of output alone for scripting. You would have to scan the output of these commands, limiting their usefulness for this question.Menace
Oddly enough, I've recently discovered that dpkg-query used to return 1 on a missing package, now ( Ubuntu 12.04 ) returns 0, causing all sorts of trouble on my jenkins build node setup script! dpkg -s returns 0 on package installed, and 1 on package not installed.Mcmurray
Hey, OP asked for if usage. I am also looking for if usage.Daloris
@Mcmurray : I'm also using Ubuntu 12.04 and dpkg -s does return 1 on missing packages and 0 otherwise, as it should. How was different on earlier (or recent) versions?Edgy
@Menace can you explain why one can't rely on return codes? I need to use something like this and it appears to work correctly (tested on an installed and an uninstalled package in Ubuntu 16.04) when used in an if statement. Is there some scenario in which it isn't reliable?Tsunami
@Tsunami At least at the time I wrote this and was using it; the return code was not indicative of whether the package was installed or not. It was indicative solely that the dpkg process didn't encounter an error. This may have changed, and I no longer use a system that uses dpkg on a day to day basis so I can't comment further. But given that 11 other people seemed to agree with me, I think something along the lines of the return codes being inconsistent or not indicative was indeed the issueMenace
@Tsunami Look at ThorSummoner's comment and point a bit further below on a different answer that quotes my comment which described exactly the scenario I ran into.Menace
a note: dpkg -s returns zero if a package was installed and then removed - in that case it's Status: deinstall ok config-files or similar, so it's "ok" - so to me, this is not a safe test. dpkg-query -l doesnt seem to return a useful result in this case either.Extinct
dpkg -s <package> | grep Status Not the prettiest solution but you can just do a bit of string analysis on the return value for that command if you want a more detailed response.Enstatite
T
123

To be a little more explicit, here's a bit of Bash script that checks for a package and installs it if required. Of course, you can do other things upon finding that the package is missing, such as simply exiting with an error code.

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

If the script runs within a GUI (e.g., it is a Nautilus script), you'll probably want to replace the 'sudo' invocation with a 'gksudo' one.

Trumpet answered 3/5, 2012 at 20:44 Comment(7)
--force-yes seems a poor idea. From man page: "This is a dangerous option that will cause apt-get to continue without prompting if it is doing something potentially harmful. It should not be used except in very special situations. Using --force-yes can potentially destroy your system!" Using it in a script makes it even worse.Germainegerman
What does ${Status} mean?Gomar
@SaladHead See man7.org/linux/man-pages/man1/dpkg-query.1.html "Package information can be included [in showformat] by inserting variable references to package fields using the syntax “${field[;width]}”." Status is one of those fields.Trumpet
In your answer, perhaps explain how and why it works. E.g., what is the intent of -W --showformat='${Status}? What does the variable "Status" contain? Or is it literal? Why is it dpkg-query when some other answers use dpkg? Etc. (But without "Edit:", "Update:", or similar - the answer should appear as if it was written today.)Lifetime
This doesn't account for the possibility that the package may not exist at all.Jotter
@PeterKionga-Kamau That's unlikely if you're the one writing the script, but should it happen you'll get an appropriate error message from apt-get.Trumpet
@Trumpet A complete algorithm deals with unlikelyhoods. A good answer does not make assumptions about purpose. The problem with relying on an error message from apt-get is that we still don't have a mechanism to tell the calling script that the package does not exist, just a halt with an stdout error. Also, it is significantly slower than checking if the package even exists (need to read package lists, build dependency tree, read state information before not locating the package), so performance could be an issue (especially for automations involving many potentially unknown packages)Jotter
A
110

This one-liner returns 1 (installed) or 0 (not installed) for the 'nano' package...

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

even if the package does not exist or is not available.

The example below installs the 'nano' package if it is not installed...

if [ $(dpkg-query -W -f='${Status}' nano 2>/dev/null | grep -c "ok installed") -eq 0 ];
then
  apt-get install nano;
fi
Amir answered 23/3, 2014 at 15:22 Comment(8)
My variation on this: dpkg-query -W -f='${Status}' MYPACKAGE | grep -q -P '^install ok installed$'; echo $?Hairbrush
@ThorSummoner: care to explain why yours is better?Extrovert
@Extrovert I'm not sure there is an argument to be made about being objectively better. Though I'm confident the verbatim post's one-liner will execute the result output, which I wouldn't want to leave dangling in an answer. The one liner I show exemplifies getting (printing) just the exit code.Hairbrush
@Hairbrush You don't need grep -P for a simple regex like that.Phototransistor
@Extrovert Anything which avoids grep -c when the task is not to actually count the number of occurrences is objectively better.Phototransistor
Simpler: if ! dpkg-query -W -f='${Status}' nano | grep "ok installed"; then apt install nano; fi -- No need to use grep -c, just use the exit status of grepHeliometer
@StephenOstermiller If your version was an answer, I would have upvoted it.Icarian
None of these account for the possibility that the package may not be installable/exist - surely that needs to be checked too. Otherwise best case is the script wasting a lot of time waiting to discover that it can't be done.Jotter
D
37

dpkg-query --showformat='${db:Status-Status}'

This produces a small output string which is unlikely to change and is easy to compare deterministically without grep:

pkg=hello
status="$(dpkg-query -W --showformat='${db:Status-Status}' "$pkg" 2>&1)"
if [ ! $? = 0 ] || [ ! "$status" = installed ]; then
  sudo apt install $pkg
fi

The $? = 0 check is needed because if you've never installed a package before, and after you remove certain packages such as hello, dpkg-query exits with status 1 and outputs to stderr:

dpkg-query: no packages found matching hello

instead of outputting not-installed. The 2>&1 captures that error message too when it comes preventing it from going to the terminal.

For multiple packages:

pkgs='hello certbot'
install=false
for pkg in $pkgs; do
  status="$(dpkg-query -W --showformat='${db:Status-Status}' "$pkg" 2>&1)"
  if [ ! $? = 0 ] || [ ! "$status" = installed ]; then
    install=true
    break
  fi
done
if "$install"; then
  sudo apt install $pkgs
fi

The possible statuses are documented in man dpkg-query as:

   n = Not-installed
   c = Config-files
   H = Half-installed
   U = Unpacked
   F = Half-configured
   W = Triggers-awaiting
   t = Triggers-pending
   i = Installed

The single letter versions are obtainable with db:Status-Abbrev, but they come together with the action and error status, so you get 3 characters and would need to cut it.

So I think it is reliable enough to rely on the uncapitalized statuses (Config-files vs config-files) not changing instead.

dpkg -s exit status

This unfortunately doesn't do what most users want:

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

because for some packages, e.g. certbot, doing:

sudo apt install certbot
sudo apt remove certbot

leaves certbot in state config-files, which means that config files were left in the machine. And in that state, dpkg -s still returns 0, because the package metadata is still kept around so that those config files can be handled more nicely.

To actually make dpkg -s return 1 as desired, --purge would be needed:

sudo apt remove --purge certbot

which actually moves it into not-installed/dpkg-query: no packages found matching.

Note that only certain packages leave config files behind. A simpler package like hello goes directly from installed to not-installed without --purge.

Tested on Ubuntu 20.10.

Python apt package

There is a pre-installed Python 3 package called apt in Ubuntu 18.04 which exposes an Python apt interface!

A script that checks if a package is installed and installs it if not can be seen at: How to install a package using the python-apt API

Here is a copy for reference:

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

Check if an executable is in PATH instead

See: How can I check if a program exists from a Bash script?

See also

Definiendum answered 17/1, 2019 at 15:49 Comment(4)
Ciro, ou can't rely on "dpkg -s" exit code. For example if you "apt installed" a package, then "apt remove" it and tried to "dpkg -s packagename" then you'll notice status: deinstall and exit code zero (as if installed). You have to parse the "dpkg -s" output bro.Rachele
@DmitryShevkoplyas thanks for the report. I could not reproduce on Ubuntu 19.10 with: sudo apt install hello; dpkg -s hello; echo $?; sudo apt remove hello; dpkg -s hello; echo $?. Can you provide further details?Definiendum
indeed - for your test case with "hello" package "dpkg -s" correctly shows the package as not installed and gives expected exit code "1". But try the same instal/remove check with package "certbot", then you'll see "Status: deinstall ok config-files" as the "dpkg -s" output after your "apt remove certbot" and exit code is incorrectly shows us "0". My wrong assumption was that it is exact case for any other package, but it seems it is not the same for all, which even worse and less predictable. Parse "dpkg -s" you must (c) Yoda :)Rachele
The information that dpkg remove package-name does not result in dpkg -s package-name returning 0 is missing in most answers which almost drove me crazy. It actually results in state deinstalled instead of just not installed! Puhh, Debian is ... peculiar.Infamous
C
12

Ubuntu added its "Personal Package Archive" (PPA), and PPA packages have a different result.

  1. A native Debian repository package is not installed:

    ~$ dpkg-query -l apache-perl
    ~$ echo $?
    1
    
  2. A PPA package registered on the host and installed:

    ~$ dpkg-query -l libreoffice
    ~$ echo $?
    0
    
  3. A PPA package registered on the host, but not installed:

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

Also posted on: Test if a package is installed in APT

Chicle answered 23/5, 2012 at 13:12 Comment(1)
If you install and remove a package, next you use dpkg-query package ; echo $? will be 0 also if the package is not installed.Vocalize
M
8

UpAndAdam wrote:

However you can't simply rely on return codes here for scripting

In my experience you can rely on dkpg's exit codes.

The return code of dpkg -s is 0 if the package is installed and 1 if it's not, so the simplest solution I found was:

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

It works fine for me...

Myeloid answered 22/9, 2014 at 13:2 Comment(4)
After apt-get remove <package>, dpkg -s <package> still returns 0, even though the package is deinstalledHairbrush
@ThorSummoner: Conclusion?Lifetime
Really short and to the point. Plus good explanation. Thanks rocka84 @Hairbrush can you clarify your point?Annual
@KasirBarati that, the return code isn't consistent for uninstalled and deinstalled packages- in both cases the software is missing, but in half the cases the return code indicates the software is missing. i think? its been a while since I've looked at thisHairbrush
V
7

I've settled on one based on Nultyi's answer:

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

Basically, the error message from dpkg --get-selections is far easier to parse than most of the others, because it doesn't include statuses like "deinstall". It also can check multiple packages simultaneously, something you can't do with just error codes.

Explanation/example:

$ 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

So grep removes installed packages from the list, and awk pulls the package names out from the error message, resulting in MISSING='python3-venv python3-dev jq', which can be trivially inserted into an install command.

I'm not blindly issuing an apt-get install $PACKAGES, because as mentioned in the comments, this can unexpectedly upgrade packages you weren't planning on; not really a good idea for automated processes that are expected to be stable.

Vaucluse answered 5/2, 2018 at 4:15 Comment(2)
I like this solution. Concise and tests for multiple packages at once. Also, you could make the optional check something as simple as [[ ! -z $MISSING ]] && sudo apt-get install $MISSINGInstruct
Note that this will miss packages which have been installed and then removed, because the output ends with 'deinstall'. Suggest changing the grep argument to grep -v ' install$' (note the leading space)Allies
B
6

This seems to work pretty well.

$ sudo dpkg-query -l | grep <some_package_name> | wc -l
  • It either returns 0 if not installed or some number > 0 if installed.
Borek answered 20/8, 2013 at 17:52 Comment(4)
grep | wc -l is an antipattern. To check if something exists, you want simply grep -q. To actually count occurrences (which is rarely useful in this sort of scenario), use grep -c.Phototransistor
@Phototransistor So, dpkg -s zip | grep -c "Package: zip"? (using zip as sample package)Venality
@Davdriver That's not exactly what the above does but yes. In a script you probably want grep -q 'Package: zip' to return an exit code which indicates whether or not the result was found without printing anything.Phototransistor
this seems working fine for uninstalled packages tooPostprandial
W
6

This will do it. apt-get --no-upgrade install is idempotent.

sudo apt-get install --no-upgrade command
Width answered 5/4, 2016 at 0:0 Comment(4)
There are scenarios in which doing an apt-get install on a package is undesirable where the package is already installed, even though the command itself is idempotent. In my case, I'm installing a package on a remote system with Ansible's raw module, which will report the system as changed every time if I run apt-get install indiscriminately. A conditional solves that problem.Tsunami
@Tsunami That's a good point. Packages that are installed as part of a dependency will get marked as manually installed, and then will not be removed when it's dependency is removed if you apt-get install it.Width
I think you should use apt-get install --no-upgrade package-name instead if you want idempotent behavior because plain install will upgrade the package if an upgrade is available.Metamer
Good call @MikkoRantalainenWidth
G
5

It seems that nowadays apt-get has an option --no-upgrade that just does what the OP wants:

--no-upgrade Do not upgrade packages. When used in conjunction with install, no-upgrade will prevent packages listed from being upgraded if they are already installed.

Manpage from https://linux.die.net/man/8/apt-get

Therefore you can use

apt-get install --no-upgrade package

and package will be installed only if it's not.

Guffaw answered 6/5, 2019 at 14:27 Comment(0)
M
5

Inspired by Chris' answer:

#! /bin/bash

installed() {
    return $(dpkg-query -W -f '${Status}\n' "${1}" 2>&1|awk '/ok installed/{print 0;exit}{print 1}')
}

pkgs=(libgl1-mesa-dev xorg-dev vulkan-tools libvulkan-dev vulkan-validationlayers-dev spirv-tools)
missing_pkgs=""

for pkg in ${pkgs[@]}; do
    if ! $(installed $pkg) ; then
        missing_pkgs+=" $pkg"
    fi
done

if [ ! -z "$missing_pkgs" ]; then
    cmd="sudo apt install -y $missing_pkgs"
    echo $cmd
fi
Magnus answered 19/2, 2021 at 4:49 Comment(0)
O
4

I've found all solutions in previous answers can produce a false positive if a package is installed and then removed, yet the installation package remains on the system.

To replicate:

Install package apt-get install curl
Remove package apt-get remove curl

Now test the previous answers.

The following command seems to solve this condition:

dpkg-query -W -f='${Status}\n' curl | head -n1 | awk '{print $3;}' | grep -q '^installed$'

This will result in a definitive installed or not-installed.

Ontogeny answered 3/5, 2016 at 14:48 Comment(3)
not entirely, sadly - other possible results in this case are config-files - so I think a final | grep -q "installed" is really needed to get a functional exit code status.Extinct
make that | grep -q '^installed$'Extinct
Instead of -f='${Status}\n' and then piping to awk you can also just use -f='${db:Status-Status}\n'.Foreskin
I
4

Use:

apt-cache policy <package_name>

If it is not installed, it will show:

Installed: none

Otherwise it will show:

Installed: version
Islamite answered 14/7, 2017 at 18:59 Comment(0)
W
4

I think a one-liner is more elegant:

dpkg --verify command || sudo apt-get install command

Explanation: apt-get will only be called if dpkg fails to verify a current installation.

From the dpgk man page:

EXIT STATUS
       0   The requested action was successfully performed.  Or a check or assertion command returned true.

       1   A check or assertion command returned false.

       2   Fatal or unrecoverable error due to invalid command-line usage, or interactions with the system, such as accesses to the database, memory allocations, etc.
Whidah answered 7/4, 2023 at 13:34 Comment(1)
Loved this one liner, for most of the packages that come with a command this seems the best option.Haver
P
3
$name="rsync"

[ `which $name` ] $$ echo "$name : installed" || sudo apt-get install -y $name
Pensioner answered 11/9, 2015 at 14:58 Comment(2)
Related, you should use command -v <command>; not which <command>. Also see Check if a program exists from a Bash script.Erdrich
why does it output -bash: [: missing `]'Polyhedron
L
1

This feature already exists in Ubuntu and Debian, in the command-not-found package.

Lashundalasker answered 19/8, 2009 at 9:15 Comment(3)
matt@matt-ubuntu:~$ command-not-found command-not-found: command not found ... lol.Tamer
command-not-found is an interactive helper, not a tool to ensure you have the dependencies you want. Of course, the proper way to declare dependencies is to package your software in a Debian package and fill in the Depends: declaration in the package's debian/control file properly.Phototransistor
On Ubuntu 18.04, command-not-found is not installed by default: "command-not-found: command not found"Lifetime
M
1
which <command>
if [ $? == 1 ]; then
    <pkg-manager> -y install <command>
fi
Mauer answered 19/3, 2017 at 10:48 Comment(1)
Related, you should use command -v <command>; not which <command>. Also see Check if a program exists from a Bash script.Erdrich
H
1

For Ubuntu, apt provides a fairly decent way to do this. Below is an example for Google Chrome:

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

I'm redirecting error output to null, because apt warns against using its "unstable cli". I suspect list package is stable, so I think it's ok to throw this warning away. The -qq makes apt super quiet.

Hutchison answered 6/12, 2017 at 18:45 Comment(5)
this won't work properly if something is "upgradable"Ascidium
@PawelBarcik good point. I've updated the answer to handle that situation.Hutchison
You can use apt -qq list google-chrome-stable --installed this way you will only get output if package is installed and you won't need to grep the output.Bergson
Note, that apt should not be used in scripts as its output is intended for human consumption and not for scripts, so this could break any time. For scripts there is apt-get.Foreskin
@Foreskin Thanks for your comment. I mention the warning in my last paragraph. I didn't use apt-get because it didn't provide this feature.Hutchison
T
1

This explicitly prints 0 if installed else 1 using only awk:

dpkg-query -W -f '${Status}\n' 'PKG' 2>&1|awk '/ok installed/{print 0;exit}{print 1}'

or if you prefer the other way around where 1 means installed and 0 otherwise:

dpkg-query -W -f '${Status}\n' 'PKG' 2>&1|awk '/ok installed/{print 1;exit}{print 0}'

** replace PKG with your package name

Convenience function:

installed() {
    return $(dpkg-query -W -f '${Status}\n' "${1}" 2>&1|awk '/ok installed/{print 0;exit}{print 1}')
}


# usage:
installed gcc && echo Yes || echo No

#or

if installed gcc; then
    echo yes
else
    echo no
fi
Timetable answered 2/12, 2020 at 20:1 Comment(1)
in cause you want to add more than one pkgs #! /bin/bash installed() { return $(dpkg-query -W -f '${Status}\n' "${1}" 2>&1|awk '/ok installed/{print 0;exit}{print 1}') } pkgs=(xxx libgl1-mesa-dev yyy xorg-dev vulkan-tools libvulkan-dev vulkan-validationlayers-dev spirv-tools vulkan-tools libvulkan-dev vulkan-validationlayers-dev spirv-tools) missing_pkgs="" for pkg in ${pkgs[@]}; do if ! $(installed $pkg) ; then missing_pkgs+=" $pkg" fi done echo $missing_pkgs if [ ! -z "$missing_pkgs" ]; then cmd="sudo apt install -y $missing_pkgs" echo $cmd fiMagnus
M
1

Since you mentioned Ubuntu, and you want to do this programmatically(although dpkg variations can also be used but would be more complex to implement), this(which) will definitely work:

#!/bin/bash

pkgname=mutt
which $pkgname > /dev/null;isPackage=$?
if [ $isPackage != 0 ];then
        echo "$pkgname not installed"
        sleep 1
        read -r -p "${1:-$pkgname will be installed. Are you sure? [y/N]} " response
        case "$response" in
            [yY][eE][sS]|[yY]) 
                sudo apt-get install $pkgname
                ;;
            *)
                false
                ;;
        esac

else
        echo "$pkgname is installed"
        sleep 1
fi

Although for POSIX compatibility, you would want to use command -v instead as mentioned in another similar question.

In that case, which $pkgname > /dev/null should be replaced by command -v $pkgname in the above code sample.

Maplemaples answered 17/5, 2022 at 8:30 Comment(0)
V
1

the following is the most simplest way to whether a package is installed or not, just locate whether the package is absent using which command, disgard all errors, and check its exit status

which curl >/dev/null 2>&1
if [ $? -eq 0 ]; then
    echo "curl is installed."
else
    echo "curl is not installed."
fi
Vortumnus answered 7/10, 2023 at 5:56 Comment(0)
V
0

This command is the most memorable:

dpkg --get-selections <package-name>

If it's installed it prints:

<package-name> install

Otherwise it prints

No packages found matching <package-name>.

This was tested on Ubuntu 12.04.1 (Precise Pangolin).

Viewy answered 25/9, 2013 at 9:38 Comment(1)
dpkg --get-selections <package-name> doesn't set the exit code to non-zero when the package is not found.Innkeeper
G
0
apt list [packagename]

seems to be the simplest way to do it outside of dpkg and older apt-* tools.

Gagliano answered 17/7, 2017 at 23:31 Comment(1)
It is nice for manual check, but it issues a warning telling that apt is not intended for scripting - in contrast to the apt-* tools.Quintilla
T
0

I had a similar requirement when running test locally instead of in Docker. Basically I only wanted to install any .deb files found if they weren't already installed.

# 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

I guess the only problem I can see is that it doesn't check the version number of the package so if .deb file is a newer version. Then this wouldn't overwrite the currently installed package.

Telltale answered 21/8, 2018 at 17:48 Comment(0)
G
0

Kinda based off yours just a little more 'elegant'. Just because I'm bored.

#!/bin/bash
FOUND=("\033[38;5;10m")
NOTFOUND=("\033[38;5;9m")
PKG="${@:1}"
command ${PKG} &>/dev/null
if [[ $? != 0 ]]; then
    echo -e "${NOTFOUND}[!] ${PKG} not found [!]"
    echo -e "${NOTFOUND}[!] Would you like to install ${PKG} now ? [!]"
    read -p "[Y/N] >$ " ANSWER
    if [[ ${ANSWER} == [yY] || ${ANSWER} == [yY][eE][sS] ]]; then
        if grep -q "bian" /etc/os-release; then
            sudo apt-get install ${PKG}
        elif grep -q "arch" /etc/os-release; then
            if [[ -f /bin/yay ]] || [[ -f /bin/yaourt ]]; then
                yaourt -S ${PKG} 2>./err || yay -S ${PKG} 2>./err
            else
                sudo pacman -S ${PKG}
            fi
        elif grep -q "fedora" /etc/os-release; then
             sudo dnf install ${PKG}
        else
            echo -e "${NOTFOUND}[!] This script couldn't detect your package manager [!]"
            echo -e "${NOTFOUND}[!] Manually install it [!]"
        fi
    elif [[ ${ANSWER} == [nN] || ${ANSWER} == [nN][oO] ]]; then
        echo -e "${NOTFOUND}[!] Exiting [!]"
    fi
else
    echo -e "${FOUND}[+] ${PKG} found [+]"
fi
Gilligan answered 14/12, 2021 at 2:10 Comment(0)
F
0

The answers that suggest to use something along the lines of:

dpkg-query --showformat '${db:Status-Status}\n' --show $package | grep -q '^installed$'
dpkg-query --showformat '${Status}\n' --show $package | grep -q '^install ok installed$'

are correct.

But if you have the package dpkg-dev installed and you do not just want to check whether a package is installed but you also:

  • want to know whether a package is installed in a certain version
  • want to have a package in a certain architecture
  • want to see if a virtual package is provided

then you can abuse the dpkg-checkbuilddeps tool for this job:

dpkg-checkbuilddeps -d apt /dev/null

This will check whether apt is installed.

The following will check whether apt is installed in at least version 2.3.15 and grep is installed as amd64 and the virtual package x-window-manager is provided by some of the installed packages:

dpkg-checkbuilddeps -d 'apt (>= 2.3.15), grep:amd64, x-window-manager' /dev/null

The exit status of dpkg-checkbuilddeps will tell the script whether the dependencies are satisfied or not. Since this method supports passing multiple packages, you only have to run dpkg-checkbuilddeps once even if you want to check whether more than one package is installed.

Foreskin answered 15/2, 2022 at 9:51 Comment(0)
M
0

If your package has a command line interface you can check if the package exists before installing it by evaluating the output from calling it's command line tool.

Here's an example with a package called helm.

#!/bin/bash

# Call the command for the package silently
helm > /dev/null

# Get the exit code of the last command
command_exit_code="$(echo $?)"

# Run installation if exit code is not equal to 0
if [ "$command_exit_code" -ne "0" ]; then
    # Package does not exist: Do the package installation
else
   echo "Skipping 'helm' installation: Package already exists"
fi;
Missymist answered 11/10, 2022 at 10:19 Comment(0)
E
-1

I use the following way:

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
Eiffel answered 6/2, 2019 at 13:29 Comment(0)
H
-1

I use this solution as I find it most straightforward.

function must_install(){
   return "$(apt -qq list $var --installed 2> /dev/null |wc -l)"
}

function install_if() {
    unset install
    for var in "$@"
    do
        if $(must_install $var)
        then
            install+="${var} "
        fi
    done
    if [ -n "$install" ];
    then
        sudo apt-get install -qy $install
    fi
}

The neat thing is, must_install returns 1 or 0 which is then interpreted as true or false from the calling if, so we don't need any test using [].

install_if takes any number of packages separated by space.

The problem is apt is not meant to be used in scripts, so this might stop working at any time. 8)

Hauberk answered 12/3, 2021 at 10:17 Comment(0)
M
-1

All the answers are good but seem to be complex for beginners like myself to understand. so here is the solution that worked for me. My Linux environment is centOS but can't confirm it works for all distributions

PACKAGE_NAME=${PACKAGE_NAME:-node}

if ! command -v $PACKAGE_NAME > /dev/null; then
    echo "Installing $PACKAGE_NAME ..."
else
    echo "$PACKAGE_NAME already installed"
fi
Making answered 24/5, 2022 at 9:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.