14

I'm trying to automate my setup as much as possible.

To do this I have lists of packages that I want to install, for example: banshee wireshark audacity thunderbird thunderbird-lightning calibre deluge unison-gtk usb-creator-kde ding digikam chromium-browser bleachbit soundconverter kdenlive firefox-kde-support vlc kwrite openjdk-6-jre icedtea6-plugin virtualbox virtualbox-guest-additions-iso.

I want to write a small bash script to call apt-get to install these packages only if they're not already installed.

Currently I have this but it doesn't work:

dpkg -s "$1" > /dev/null 2>&1 || apt-get -y install "$1", (where $1 is the list)

Bruno Pereira
  • 73,643
happyskeptic
  • 1,006

5 Answers5

5

apt-get will fairly silently skip over any package that is installed already so I'm not sure why it needs to get special treatment? ie:

root@bun:~# apt-get -y install  vlc
Reading package lists... Done
Building dependency tree       
Reading state information... Done
vlc is already the newest version.

Is there a particular reason this won't work for you as-is?

Caesium
  • 15,807
  • 1
    I guess I could. The reason I didn't consider it first-off is I use this as part of an automated script that does all my configuration (all config files, network setup etc.). That means whenever I change anything at all I need to re-run this script on two separate machines so wanted it to run in as short a time as possible. Running apt-get, especially on the laptop which might not always have an internet connection, is quite heavy-weight in terms of the time it takes. – happyskeptic Jan 24 '12 at 14:37
  • Further to the above this works on rpm-based systems with rpm -q, it simply looks in the local db of installed packages and is very quick, and importantly doesn't need to time out in case there is no network. – happyskeptic Jan 24 '12 at 14:39
  • 3
    One reason to avoid invoking apt-get -y install with already-installed package names is apt-get will change the status of auto-installed packages to "manually installed" in this case. See https://askubuntu.com/q/831/550780 for details. – CODE-REaD Jan 23 '20 at 19:40
4

For a live session setup script, I had something like this:

# returns 1 if the package was already installed and 0 otherwise. The first
# argument is the package name to be checked (and installed if not already).
# other arguments are passed to apt-get
try_install() {
    dpkg -l "$1" | grep -q ^ii && return 1
    apt-get -y install "$@"
    return 0
}

if try_install openssh-server; then
    sed /etc/ssh/sshd_config 's/UsePAM yes/UsePAM no/' -i
    reload ssh
fi
try_install screen && wget lekensteyn.nl/files/screenrc -O ~/.screenrc
# passing extra options and package names to apt-get
try_install firefox --no-install-recommends firefox-kde-support

If an application was already installed, I assumed it to be configured.

Lekensteyn
  • 174,277
2

I went back over my asked questions on this site and realised I never posted the commands I ended up using:

export DEBIAN_FRONTEND=noninteractive # stop annoying prompts
dpkg -s "$@" > /dev/null 2>&1 || apt-get -qq -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install "$@"
happyskeptic
  • 1,006
0

This is what I'm using in my ~/.bash_aliases:

apt_install() {
    # Avoid marking installed packages as manual by only installing missing ones
    local pkg=
    local pkgs=()
    local ok
    for pkg in "$@"; do
        # shellcheck disable=SC1083
        ok=$(dpkg-query --showformat=\${Version} --show "$pkg" 2>/dev/null || true)
        if [[ -z "$ok" ]]; then pkgs+=( "$pkg" ); fi
    done
    if (("${#pkgs[@]}")); then
        sudo apt install "${pkgs[@]}"
    fi
}

Usage:

$ apt_install python3 git-restore-mtime gedit gnome-cards-data trash-cli
Reading package lists... Done
Building dependency tree       
Reading state information... Done
The following NEW packages will be installed:
  git-restore-mtime trash-cli
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Need to get 38.0 kB of archives.
...
MestreLion
  • 20,086
0

You may try saving a list of already installed packages via dpkg --get-selections > installed-software

Now, you may use other tools to find which packages should be installed, e.g:

vadik@ubuntu:~$ cat installed-software | grep "indicator-weather"
indicator-weather               install
vadik@ubuntu:~$ cat installed-software | grep "indicator-cpufreq"
vadik@ubuntu:~$ 

As you may see, you can determine whether indicator-weather or indicator-cpufreq are installed using grep