282

I want my cron-run reporting script to notify me in case there are updates for my packages. Is the a way to make apt-get give me the list of available updates but don't do anything more?

Braiam
  • 35,991
Morris
  • 2,829
  • 2
  • 15
  • 3

16 Answers16

319

apt

For modern versions of apt there is a specific switch for this:

apt list --upgradable

apt-get

For the old apt-get command the -u switch shows a list of packages that are available for upgrade:

# apt-get -u upgrade --assume-no

From the apt-get man page:

-u
--show-upgraded
 Show upgraded packages; Print out a list of all packages that are to be upgraded. Configuration Item: APT::Get::Show-Upgraded.
--assume-no  Automatic "no" to all prompts. &lt== To prevent it from starting to install
jasonwryan
  • 73,126
  • 5
    I was hoping this could be done without root – ThorSummoner Feb 06 '15 at 17:33
  • 19
    If you type "Y" and press Enter, this command will install updates. I would definitely recommend to add "-s", otherwise this answer is misleading – Murmel Jun 17 '15 at 07:26
  • 5
    This is a very wrong answer because (without additional options) the command waits for input and if the user enters the wrong input, the package are installed, which modifies the system which is not what the OP wants (just happened on my system) – Daniel Alder Nov 01 '15 at 13:11
  • And btw: -u is a default option of apt-get – Daniel Alder Nov 01 '15 at 13:17
  • 1
    @ThorSummoner '-s' will do what you want & works without root – nevelis Dec 16 '15 at 23:47
  • @nevelis Ah and your comment is reflected in this answer too, perfect! http://unix.stackexchange.com/a/86335/61349 – ThorSummoner Dec 17 '15 at 17:24
  • I prefer the first option because does not require sudo. The second does. – Pedro Luz Sep 18 '18 at 14:29
  • apt list --upgradable is not an equivalent of apt-get -u upgrade --assume-no .. the former will only respect UPgrades, no downgrades, while the latter does respect downgrades - i would consider the latter to be the better universal option – Eugen Mayer Nov 16 '18 at 08:55
  • On my Debian9, the "apt list --upgradeable" command isn't recognised. Try "apt list --upgradable" instead. Not sure if that's a typo or just a difference between Debian9 and other systems. – Dmitri Sologoubenko Jun 03 '20 at 07:18
  • There isn't a parameter --assume-no in apt-get man page; instead, there is a similar parameter --trivial-only – dpinya Oct 20 '21 at 11:18
  • apt list --upgradable is not well suited for a cron-job:
    1. It will emit a warning about its "unstable" API and therefore
    2. it will always produce output and generate mails even if there are no packages to upgrade
    – Christo Nov 29 '21 at 15:05
72
apt-get --just-print upgrade

Is not read that easily, below is a perl one liner to parse apt-get's output:

apt-get --just-print upgrade 2>&1 | perl -ne 'if (/Inst\s([\w,\-,\d,\.,~,:,\+]+)\s\[([\w,\-,\d,\.,~,:,\+]+)\]\s\(([\w,\-,\d,\.,~,:,\+]+)\)? /i) {print "PROGRAM: $1 INSTALLED: $2 AVAILABLE: $3\n"}'

This should output something like:

PROGRAM: grub-pc INSTALLED: 1.99-21ubuntu3.1 AVAILABLE: 1.99-21ubuntu3.9

Hopefully it will help someone else,

Tom
  • 721
  • 1
    just for the laugh: apt-get -s upgrade| awk -F'[][() ]+' '/^Inst/{printf "Prog: %s\tcur: %s\tavail: %s\n", $2,$3,$4}' – tink May 17 '13 at 03:19
  • 10
    It could also be much more nice looking, if use column like this: apt-get --just-print upgrade 2>&1 | perl -ne 'if (/Inst\s([\w,\-,\d,\.,~,:,\+]+)\s\[([\w,\-,\d,\.,~,:,\+]+)\]\s\(([\w,\-,\d,\.,~,:,\+]+)\)? /i) {print "PROGRAM: $1 INSTALLED: $2 AVAILABLE: $3\n"}' | column -s " " -t – AntonioK Jul 14 '15 at 11:35
  • 1
    @AntonioK Looks great! – nick Nov 10 '16 at 05:47
  • 2
    I'm afraid this Perl-code will hack my machine... ;) – Chris Jun 26 '18 at 15:14
  • @AntonioK How do you sort the names of the programs alphabetically? – Richie Jan 29 '20 at 12:51
  • @Richie Copy the output and paste into something easier to sort. – mbomb007 Apr 20 '21 at 20:33
40

Another option, inspired by enzotib :

aptitude search '~U' | wc -l

This command will use aptitude to output the new packages and then wc to just count the lines.

On a sidenote, I found that enzotib's solution without the single quotes around the ~U didn't work for me. (Wheezy, ZSH, aptitude 0.6.8.2)

Update :

With the new apt you can do:

apt list --upgradeable

tjoels
  • 7
cete3
  • 566
31

The easiest is:

apt list --upgradeable

tjoels
  • 7
AJM
  • 411
  • 4
  • 3
21

You can run

aptitude -F%p --disable-columns search ~U

or the undocumented

/usr/lib/update-notifier/apt-check -p; echo

Another method using an apt-get simulation:

apt-get -s dist-upgrade | awk '/^Inst/ { print $2 }'
enzotib
  • 51,661
  • 1
    This aptitude command worked great for me and did not require root – JamesCW May 05 '16 at 18:22
  • apt-get -s dist-upgrade works good too and has same output when you pipe it through that awker – ychaouche Feb 09 '17 at 09:28
  • thank you! this got out of quite a bit of dependency hell. was trying to dist-upgrade but not lose some packages so needed to use aptitude. aptitude install $(apt-get -s dist-upgrade | awk '/^Inst/ { print $2 }') did the trick! – Jayen Dec 03 '17 at 10:18
14
apt-get update && apt-get -s upgrade

will list available updates without actually installing.

First command updates package index files before simulated (thus -s) upgrade is done. "-s" will do a simulated upgrade showing packets that would be installed but will not actually install anything.

On the contrary "-u" instead of "-s" would actually install after confirmation.

ajaaskel
  • 424
  • 3
    The simulate option can be triggered with any of -s, --simulate, --just-print, --dry-run, --recon, --no-act, recon and dry-run are my personal favorites. – ThorSummoner Dec 17 '15 at 17:24
12

Take a look at package "apticron":

apticron - Simple tool to mail about pending package updates

Apticron is a simple script which sends daily emails about pending package updates such as security updates, properly handling packages on hold both by dselect and aptitude.

https://packages.debian.org/buster/apticron

f4m8
  • 1,989
  • 1
  • 11
  • 5
10

I needed full version information on possible upgrades, so I used a modification of jasonwryan's answer:

apt-get -V -u upgrade

It's simple and IMO reasonably formatted output.

Ben Brian
  • 261
5
apt-get update > /dev/null && apt-get --just-print upgrade | grep "Inst "

is the most simple for cron emails; there is no user iteration, and if there are no updates there is no output.

user1133275
  • 5,574
4

Just filter the output of

apt-get update && apt-get -s -V -u upgrade

to have only the preferred information in your log.

Most likely, you'll need the beautiful part after the line

...

The following packages will be upgraded:

...

that has few spaces in the beginning.

freealx
  • 41
  • Hi and welcome to the site. As it stands, your answer is basically a rehash of existing ones and so does not add anything new. You could improve it by, for example, explaining how to filter the output, adding an explanation of what the various switches do etc. – terdon Nov 19 '14 at 17:29
3

Jet another on-liner, inspired by this answer:

function a { read input;dpkg -l ${input} | grep " ${input} " | awk '{$1=$2=$3=$4="";print $0}' | sed 's/^ *//';unset input;};{ apt-get --just-print upgrade 2>&1 | perl -ne 'if (/Inst\s([\w,\-,\d,\.,~,:,\+]+)\s\[([\w,\-,\d,\.,~,:,\+]+)\]\s\(([\w,\-,\d,\.,~,:,\+]+)\)? /i) {print "$1 (\e[1;34m$2\e[0m -> \e[1;32m$3\e[0m)\n"}';} | while read -r line; do echo -en "$line $(echo $line | awk '{print $1}' | a )\n"; done;

The output looks like this (colored):

locales (2.13-38+deb7u7 -> 2.13-38+deb7u8) Embedded GNU C Library: National Language (locale) data [support]
linux-headers-3.2.0-4-amd64 (3.2.65-1+deb7u1 -> 3.2.65-1+deb7u2) Header files for Linux 3.2.0-4-amd64
linux-headers-3.2.0-4-common (3.2.65-1+deb7u1 -> 3.2.65-1+deb7u2) Common header files for Linux 3.2.0-4
sudo (1.8.5p2-1+nmu1 -> 1.8.5p2-1+nmu2) Provide limited super user privileges to specific users

If you dont want the short description use this one:

{ apt-get --just-print upgrade 2>&1 | perl -ne 'if (/Inst\s([\w,\-,\d,\.,~,:,\+]+)\s\[([\w,\-,\d,\.,~,:,\+]+)\]\s\(([\w,\-,\d,\.,~,:,\+]+)\)? /i) {print "$1 (\e[1;34m$2\e[0m -> \e[1;32m$3\e[0m)\n"}';} | while read -r line; do echo -en "$line\n"; done;

Output:

locales (2.13-38+deb7u7 -> 2.13-38+deb7u8)
linux-headers-3.2.0-4-amd64 (3.2.65-1+deb7u1 -> 3.2.65-1+deb7u2)
linux-headers-3.2.0-4-common (3.2.65-1+deb7u1 -> 3.2.65-1+deb7u2)
sudo (1.8.5p2-1+nmu1 -> 1.8.5p2-1+nmu2)
3

apt-check is probably the most efficient scripting method.

/usr/lib/update-notifier/apt-check 2>&1 | cut -d ';' -f 1

A very small modification shows you only the security updates.

/usr/lib/update-notifier/apt-check 2>&1 | cut -d ';' -f 2
flickerfly
  • 1,651
3

I like to use this:

apt-get -qq update && apt-get -qq -s upgrade

You get an output like this one:

Inst linux-base [3.5] (4.5~deb8u1 Debian-Security:8/oldstable [all])
Conf linux-base (4.5~deb8u1 Debian-Security:8/oldstable [all])

if there are available updates, and none if there isn't. This way you can simply couple it with a monitoring solution.

2

After writing warning to @jasonwryan's answer, I want to provide my own solution:

apt-get dist-upgrade --assume-no

Unfortunately, this one doesn't work with debian wheezy and I had to check some lxc containers which are still not upgraded. This form will always work:

apt-get dist-upgrade </dev/null

Finally, I also wanted to reformat the output. I chose to change the call again (using --dry-run but ignoring all additional output) because it feels more safe:

apt-get --dry-run dist-upgrade | awk '
BEGIN{p=0}
/^The/{p=1;t=$0}
/no longer required/{p=0}
#optional: /been kept back/{p=0}
p && t{print t;t=""}
/^  / && p{print $0}
'

Returns:

The following packages have been kept back:
  iproute
The following packages will be upgraded:
  unzip
2

There's the apt-show-versions tool. To show available updates run:

apt-show-versions -u
agc
  • 7,223
1

As a variation I use the following:

apt-get -V -s dist-upgrade \
    |grep -E "^   .*=>.*" \
    |awk 'BEGIN {
        ul=sprintf("%*s",40,""); gsub(/ /,"-",ul);
        printf "%-30s %-30s %-30s\n", "Package", "Installed", "Available";
        printf "%-30.30s %-30.30s %-30.30s\n", ul, ul, ul;
     }
     {
        printf "%-30s %-30s %-30s\n",
               $1,
               substr($2,2),
               substr($4,1,length($4)-1)
     }'

Stick it into a script named apt-updates and you can then call apt-updates to get a listing of all updates regardless of user.

You still do need to call apt-get update with privileged access.

  • output only shows the package name (first column), second column always prints "=" and third column is always empty. I'm on Mint. – ychaouche Feb 09 '17 at 10:15