Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

Sometimes your scripts need to behave differently on different Linux's. How can I determine which version of Linux a script is running on?

share|improve this question
1  
By version, do you mean the kernel version? What distribution? The distro version? –  Chris Upchurch May 2 '09 at 23:14
2  
I'm sure jldugger wants to find out which distribution family the system is running. It's unlikely a script would be affected by the kernel version unless it depends on some /sys or /proc stuff - and even then it's usually easier to assume based on distribution than on kernel. –  Mihai Limbăşan May 2 '09 at 23:18

14 Answers 14

up vote 25 down vote accepted

Don't try and make assumptions based on the distro as to what you can and cannot do, for that way lies madness (see also "User Agent detection"). Instead, detect whether what it is that you want to do is supported, and how it's done by whatever command or file location you want to use.

For example, if you wanted to install a package, you can detect whether you're on a Debian-like system or a RedHat-like system by checking for the existence of dpkg or rpm (check for dpkg first, because Debian machines can have the rpm command on them...). Make your decision as to what to do based on that, not just on whether it's a Debian or RedHat system. That way you'll automatically support any derivative distros that you didn't explicitly program in. Oh, and if your package requires specific dependencies, then test for those too and let the user know what they're missing.

Another example is fiddling with network interfaces. Work out what to do based on whether there's an /etc/network/interfaces file or an /etc/sysconfig/network-scripts directory, and go from there.

Yes, it's more work, but unless you want to remake all the mistakes that web developers have made over the past decade or more, you'll do it the smart way right from the start.

share|improve this answer
    
(Expanding on this answer) Feature-detection is preferable in some situations, but make sure you never try and guess the distribution from the features you detect! Don't misread the answer and work out whether the platform is RedHat based on what files are in /etc. If you really do need the distribution name, check lsb_release (or /etc/redhat-release, and so on). –  Nicholas Wilson May 22 '13 at 9:55

You can find the kernel version by running uname -a, finding the distro version is dependant on the distro.

On Ubuntu and some other OS' you can run lsb_release -a or read /etc/lsb_release

Debian stores the version in /etc/debian_version

share|improve this answer
    
+1 for lsb_release (also works on Red Hat derivatives if the right package is installed) –  Josh Kelley Jun 10 '09 at 10:52
    
for just the description 'lsb_release -ds'. –  flickerfly Sep 12 at 16:12

There is no cross-distribution way. However:

  • Redhat and friends: Test for /etc/redhat-release, check contents
  • Debian: Test for /etc/debian_version, check contents
  • Mandriva and friends: Test for /etc/version, check contents
  • Slackware: Test for /etc/slackware-version, check contents

Etc. Generally speaking, check for /etc/*-release and /etc/*-version.


Edit: Found an old (1+ years) bash script of mine lying around that I must have cobbled together over the years (it has an impressive CVS log going back 6 years.) It might not work properly anymore as-is and I can't be bothered to find installed distros to test against, but it should provide you with a good starting point. It works fine on CentOS, Fedora and Gentoo. gyaresu tested it successfully on Debian Lenny.

#!/bin/bash

get_distribution_type()
{
    local dtype
    # Assume unknown
    dtype="unknown"

    # First test against Fedora / RHEL / CentOS / generic Redhat derivative
    if [ -r /etc/rc.d/init.d/functions ]; then
        source /etc/rc.d/init.d/functions
        [ zz`type -t passed 2>/dev/null` == "zzfunction" ] && dtype="redhat"

    # Then test against SUSE (must be after Redhat,
    # I've seen rc.status on Ubuntu I think? TODO: Recheck that)
    elif [ -r /etc/rc.status ]; then
        source /etc/rc.status
        [ zz`type -t rc_reset 2>/dev/null` == "zzfunction" ] && dtype="suse"

    # Then test against Debian, Ubuntu and friends
    elif [ -r /lib/lsb/init-functions ]; then
        source /lib/lsb/init-functions
        [ zz`type -t log_begin_msg 2>/dev/null` == "zzfunction" ] && dtype="debian"

    # Then test against Gentoo
    elif [ -r /etc/init.d/functions.sh ]; then
        source /etc/init.d/functions.sh
        [ zz`type -t ebegin 2>/dev/null` == "zzfunction" ] && dtype="gentoo"

    # For Slackware we currently just test if /etc/slackware-version exists
    # and isn't empty (TODO: Find a better way :)
    elif [ -s /etc/slackware-version ]; then
        dtype="slackware"
    fi
    echo $dtype
}

Note that this will probably only work correctly in Bash. You could rewrite it ofr other shells.

That being said, you might want to test for features, not for distributions. I'm not using this anymore simply because it became a maintenance burden. It's easier to rely on cross-distribution tools and solutions.


Conceptually, what it does is, in order:

  • Pull in a known, "common init script function" type of file. Those are distribution-specific. If it doesn't exist, skip to next distribution check.
  • Check the existence of a specific, known-to-exist, often-used and unlikely to be renamed function from that core script. We do that using the type Bash builtin. type -t returns function if that symbol is a function. We prepend zz to the output from type -t 2>/dev/null because if the name isn't defined the output string would be empty and we'd get a syntax error about a missing left hand to the == operator. If the name we just checked isn't a function, skip to next distribution check, otherwise we found the distribution type.
  • Finally, echo the distribution type so the function output can be easily used in a case .. esac block.


Edit in case you're trying to run this as a straight script: This script is supposed to get sourced or included from other scripts. It does not output anything on its own if you run it as-is. To test it, source it and then invoke the function, e.g.:

source /path/to/this/script.sh
get_distribution_type

at the bash prompt.<

share|improve this answer
    
I haven't looked at why but it returns to prompt on Debian Lenny (5.0). –  gyaresu May 3 '09 at 0:39
    
gyaresu, have you actually invoked the get_distribution_type function? I've edited the post to clarify (see at the bottom.) –  Mihai Limbăşan May 3 '09 at 0:51
    
@gyaresu: If the above wasn't the problem, can you please try to replace log_begin_msg in the Debian section with log_warning_msg and retry? Might have gotten the function name wrong. In any case, it should have returned "unknown" if that function wasn't htere, but still. –  Mihai Limbăşan May 3 '09 at 1:20
    
@Mihai Doh! Sorry. Didn't read the script properly. Was early, no coffee. My apologise. gyaresu@debian:~/bin$ source server_version.sh gyaresu@debian:~/bin$ get_distribution_type debian –  gyaresu May 3 '09 at 6:33
    
@gyaresu: Thanks! That's good, should help jldugger to know that it works on Debian as well :) –  Mihai Limbăşan May 3 '09 at 7:24

In addition to the other answers: If you just want to parse one file, most distros personalize the tty login via /etc/issue e.g.:

Welcome to SUSE Linux Enterprise Server 10 SP2 (i586) - Kernel \r (\l).

And yes I know it's suboptimal. :)

share|improve this answer
    
It may be sub-optimal, but it is in the same place. –  Brad Gilbert May 3 '09 at 3:17

Most distro's have a unique method of determining the particular distribution.

For example:

Redhat (And derivatives): /etc/redhat-release

SUSE: /etc/SUSE-release

There is a standard out there known as the Linux Standard Base or LSB. It defines that there should be a file called /etc/lsb-release or a program called lsb_release that will echo back information about your linux distro.

lsb_release -a
share|improve this answer
    
And of course, lsb_release does not exist on CentOS 6. –  Justin Sep 21 '12 at 2:45

The version of linux is a hard question. If we look at it narrowly we have the kernel version you can get with "uname -r". Distribution version is mostly irrellevant. Some distributions are better (enterprise distributions such as Redhat Enterprise Linux). Other distributions like Gentoo are basically moving targets that have no sensible version at all. If you need to do things based on version, take a look at major components that are relevant to you:

Component       Version command
glibc           /lib/libc.so.6
gcc             gcc --version
X               xdpyinfo
libX11          pkg-config --modversion x11
gtk+            pkg-config --modversion gtk+-2.0
qt-4            pkg-config --modversion QtCore

   etc...
share|improve this answer

facter is a handy tool for this sort of discovery, although it probably uses some of the methods detailed above, and requires Ruby.

share|improve this answer

All you need to do is type uname -a at your favorite shell. That will print out the kernel name and version.

share|improve this answer

You can also get the version by

cat /proc/version

o/p:

Linux version 2.6.17-13mdv (rtp@octopus.mandriva.com) (gcc version 4.1.2 20070302 (prerelease) (4.1.2-1mdv2007.1)) #1 SMP Fri Mar 23 19:03:31 UTC 2007

share|improve this answer

You can also check the Grub menu, usually gives you a bunch of distro/version info :-)

share|improve this answer

I've found that cat /etc/*release* almost always works.

share|improve this answer

I concur with Mark, Adam and Mihai (can't vote up due to insufficient reputation). Solutions based on LSB and its relative FHS will work with most distributions and are likely to continue working in future. LSB and FHS are your friends.

share|improve this answer
python -c 'import platform ; print platform.dist()[0]'

code: http://hg.python.org/cpython/file/2.7/Lib/platform.py

share|improve this answer
    
Great idea. I would suggest using python -c 'import platform; print(platform.dist()[0])', because that way it also works if the normal python defaults to python3. –  heinrich5991 Dec 9 '12 at 14:11

FusionInventory is a cross-platform lightweight inventory tool that can get this information on many Linux distros but also on BSDs, Windows, MacOS X and other unices.

If available, they use lsb_release (as mentioned a few times above), but if not they have a very useful list of files and regular expressions to check the distro name and version: https://github.com/fusinv/fusioninventory-agent/blob/2.2.x/lib/FusionInventory/Agent/Task/Inventory/Input/Linux/Distro/NonLSB.pm#L16.

I would recommend using FusionInventory itself to get this information, rather than reimplementing your own scripts with this logic, as their community will maintain this functionality up to date. You could either use the agent on it's own (it outputs a XML/JSON file which is easy to parse) or couple it with a wider solution to manage the machines in your network like GLPI or Rudder, depending on your needs.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.