22

I am trying to create a script that requires me to print the Debian codename so that I may echo it into the sources.list file.

I am trying to make this script work across any version of Debian, so I had hoped to set a bash variable of the release codename. This would be simple to do with lsb_release -c. However, our deployment images do not contain lsb_release by default - and with this script being required to fix the sources.list, installing lsb-release with apt-get would not be an option.

I have found numerous ways to get the release number and other info about the system, but cannot find a reliable place to get the codename.

(I am testing this with Debian Squeeze.)

1
  • 2
    If you googled this while considering dropping lsb_release, check out it's source code and see if you're willing to reinvent all that Jan 30, 2020 at 11:55

12 Answers 12

28

You can use /etc/os-release:

(
  . /etc/os-release
  printf '%s\n' "$VERSION"
)
7 (wheezy)
20

For Debian distributions that don't ship with /etc/os-release (like Squeeze), you can use the following "hack". It exploits that the tzdata package provides a capability(1) that includes that name:

$ dpkg --status tzdata
Package: tzdata
...
Provides: tzdata-squeeze

So, you can post-process this to extract that part of the capability name:

dpkg --status tzdata|grep Provides|cut -f2 -d'-'

or, with less piping

dpkg --status tzdata|awk -F'[:-]' '$1=="Provides"{print $NF}'

(1) that's RedHat terminology, though

1
  • 1
    Yooo, bro. This is sick! Exactly what I needed. Anything else in Linux Mint LMDE (Debian Edition) doesn't display the Debian version that the Mint was built on. But your solution does. Thanks!
    – GTodorov
    Aug 16, 2019 at 15:36
11

You can get the codename of your Debian distribution from /etc/os-release. Instead of attempting to parse this file, you can source it into a fresh environment, so as not to impact your current environment, and execute an echo command in that new environment.

env -i bash -c '. /etc/os-release; echo $VERSION_CODENAME'

To break it down:

  • env : Run a command in a new environment.
  • -i : Do not inherit the environment variables from the existing environment.
  • bash : Run bash so that we have a shell to source the os-release file into, and to run the echo command.
  • -c : Tell bash we want to execute a command rather than start an interactive shell.
  • . /etc/os-release : Source the contents of os-release into our new environment. os-release contains a few lines setting environment variables, and this will set those environment variables in our new environment.
  • ; : Separate this command and run the next command.
  • echo $VERSION_CODENAME : Echo out the code name that was set by the os-release file.
3
  • 1
    Great answer, I learned you to use such files from it. I used it like this echo "$(. /etc/os-release && echo $VERSION_CODENAME" but noticed that there's no $VERSION_CODENAME in stretch. Very sad news.
    – Himura
    Oct 14, 2019 at 11:03
  • 2
    I fixed it like this echo "$(. /etc/os-release && echo ${VERSION_CODENAME-stretch})" which seems ok for my task, but it looks bad
    – Himura
    Oct 14, 2019 at 11:08
  • 1
    This looks like the most elegant approach (at least thanks to no parsing involved) Jan 30, 2020 at 11:53
6

You can print code along with version number of debian:

root@debian:/home/mohsen# grep "VERSION=" /etc/os-release |awk -F= {' print $2'}|sed s/\"//g
8 (jessie)

OR you can bare your code name from number and pranthese:

grep "VERSION=" /etc/os-release |awk -F= {' print $2'}|sed s/\"//g |sed s/[0-9]//g | sed s/\)$//g |sed s/\(//g
jessie
4
  • Or, more idiomatically: awk -F= '/VERSION=/ {gsub(/"/,""); print $2}' /etc/os-release
    – jasonwryan
    Jan 24, 2015 at 3:58
  • 1
    @jasonwryan Even awk -F"[=\"]+" '/VERSION=/ {print $2}' /etc/os-release
    – Costas
    Jan 24, 2015 at 12:41
  • @Costas my output is only codename. Jan 24, 2015 at 13:07
  • 4
    If you'd like just code-name it is much simple awk -F"[)(]+" '/VERSION=/ {print $2}' /etc/os-release
    – Costas
    Jan 24, 2015 at 13:28
2

For systemd:

hostnamectl | grep "Operating System"

output:

  Operating System: Debian GNU/Linux 8 (jessie)
2
  • It works for me.
    – Anthony
    Jan 14, 2017 at 9:21
  • This surely does not work on Debian Squeeze as Debian Squeeze did not have a systemd package. And even with Debian 8 Jessie (where systemd became the default init system), hostnamectl is only installed if systemd is installed, so this solution won't work if the system in question uses one of the other 3 or 4 init systems Debian offers. Apr 6, 2017 at 13:06
1

this one might (or might not) be an alternate approach to what bcoca wrote on Debian squeeze - i tested it Ubuntu 18.04:

$ cat /etc/debian_version
buster/sid
0

Another heuristic is to see where the packages for the currently running OS come from.

Simple (and probably error-prone) variant:

fgrep -r /debian/ /etc/apt/sources.list \
    | egrep -v '^ *#' \
    | awk '{print $3}' \
    | egrep -v '[-/]'  \
    | uniq

A more reliable way is to parse the details out of the output of apt-cache policy (without further parameter):

apt-cache policy \
    | fgrep o=Debian, \
    | fgrep ,l=Debian, \
    | fgrep ,c=main, \
    | awk -F '[,=]' '{print $6}'

apt-cache policy lists all APT repositories in use on the local system. We filter out those which originate from Debian, which are labeled just Debian (i.e. not those labeled e.g. Debian debug), then only look at the main archive (not contrib or non-free) and then select the according value.

An even more stable approach would be to not rely on the element order and find the n= value in the remaining line:

apt-cache policy \
    | fgrep o=Debian, \
    | fgrep ,l=Debian, \
    | fgrep ,c=main, \
    | egrep -o 'n=[^, ]*' \
    | awk -F= '{print $2}'

Yet another possibility would be to parse the /var/lib/apt/lists/*Release files yourself instead of letting apt-cache do that:

egrep -l '^Origin: Debian$' /var/lib/apt/lists/*Release \
    | xargs egrep -l '^Label: Debian$' \
    | xargs egrep -L 'Codename: .*-' \
    | xargs fgrep Codename \
    | awk '{print $2}'
0

My need was to add some URL in sources.list. And to be able to dynamically put version code name, I use this piece of code (rely on the fact that code name is between parenthesis) : Inspired by @PersianGulf answer.

grep "VERSION=" /etc/os-release |awk -F= {' print tolower($2)'}|sed s/\.*\(//g | sed s/" ".*\"//g

0

Expanding upon @Costas answer, that command didn't work for 16.04 where it returned the full name "Xerial Xerus" but I only wanted "xerial" as that is how the repo I was trying to pull from separated the different versions. This command adds that only the first word will be returned, and that it will be all lowercase:

awk -F"[)(]+" '/VERSION=/ {print $2}' /etc/os-release | awk '{print $1}' | awk '{ print tolower($0) }'

This works for "jessie" as well

0

Only using grep:

grep -Po 'VERSION="[0-9]+ \(\K[^)]+' /etc/os-release

Try it (output as of writing this post):

$ docker run --rm debian:stable-slim grep -Po 'VERSION="[0-9]+ \(\K[^)]+' /etc/os-release
stretch
0

I'm going to leave this here :)

sed -e "0,/_.*_/s/.*_\(.*\)_.*/\1/;t;d" /var/lib/apt/cdroms.list

Edit: It's matching the first _<string>_ inside /var/lib/apt/cdroms.list

1
  • This did show jessie after upgrading to stretch, while env -i bash -c '. /etc/os-release; echo $VERSION_CODENAME' returned the correct version: stretch Oct 5, 2020 at 21:44
0

How to get the Debian codename without lsb_release

If you want only the codename and nothing else :

$ (. /etc/os-release; printf '%s\n' "$VERSION_CODENAME";)
bullseye

If you want to mimic lsb_release -c :

$ (. /etc/os-release; printf 'Codename: %s\n' "$VERSION_CODENAME";)
Codename: bullseye

If you want to mimic lsb_release -d :

$ (. /etc/os-release; printf 'Description: %s %s\n' "$NAME" "$VERSION";)
Description: Debian GNU/Linux 11 (bullseye)

Reference

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .