Grab ID of OS from /etc/os-release

Sourcing and awk are poor ideas

Sourcing these sorts of files with a shell script interpreter is a poor idea, as it introduces yet another place where the malicious can hide shell script to be executed with superuser permissions, or can introduce things like an override for variables like PATH, LANG, and LD_LIBRARY_PATH.

% cat /etc/os-release
PRETTY_NAME="Debian GNU/Linux 9 (stretch with subversive \$PATH)"
NAME="Debian GNU/Linux"
VERSION="9 (stretch)"
echo 1>&2 'install -m 0644 /etc/shadow /home/malefactor/etc/ 2>/dev/null'
% ( source /etc/os-release ; command -v start-stop-daemon ; )
install -m 0644 /etc/shadow /home/malefactor/etc/ 2>/dev/null

Sourcing actually violates one of the defined semantics for /etc/os-release, which is that (to quote its manual) "variable expansion is explicitly not supported".

Similarly, awk as supplied in Archemar's answer does not correctly handle quoting; and any value can be quoted. Notice how Archemar's answer does not address the VERSION value in the question, which the given awk script does not provide the correct value for, because it erroneously retains the quoting and does not handle escape sequences.

% awk -F= '$1=="VERSION" { print $2 ;}' /etc/os-release
"9 (stretch)"      
% awk -F= '$1=="PRETTY_NAME" { print $2 ;}' /etc/os-release
"Debian GNU/Linux 9 (stretch with subversive \$PATH)"

/etc/os-release is actually permitted a fairly broad latitude in quoting, and also requires that escape sequences be processed properly. awk is not really the right tool for the job at all, here.

There are other, subtler, problems such as leakage of already set variables into the results if the actual key sought is missing from the file.

% ( source /etc/os-release ; echo $LANG ; )
install -m 0644 /etc/shadow /home/malefactor/etc/ 2>/dev/null

There's also the fact that if ID or PRETTY_NAME are missing, they are defined as having default values. And on top of that, there's the fallback to /usr/lib/os-release to deal with.

Learning from other people

Files that contain key-equals-value assignments, with sh-style quoting, escaping, and commentary, are a fairly common thing. Some programming languages have library functions for dealing with them directly. The lesson of OpenBSD's rules shift on /etc/rc.conf in OpenBSD 5.6 is that it is the wiser course to use such library functions, if available, or dedicated tools that have nowhere near the capabilities of a full shell interpreter, for processing such files.

From shell scripts, I for one use a tool named read-conf to process such files:

% read_os() {
    if test -r /etc/os-release
        clearenv setenv "$1" "$2" read-conf /etc/os-release printenv "$1"
        clearenv setenv "$1" "$2" read-conf /usr/lib/os-release printenv "$1"
% read_os ID linux
% read_os VERSION
9 (stretch)
% read_os PRETTY_NAME Linux
Debian GNU/Linux 9 (stretch with subversive $PATH)
% read_os PATH
% read_os LANG

The aforegiven relies on setenv, read-conf, and printenv commands being built-in commands in the nosh toolset, so that clearenv, setenv, and read-conf each find the next command in the chain without using the PATH environment variable at all. (Before I added the built-in printenv, the slightly longer original one-liners made careful use of "`command -v printenv`" to avoid searching for printenv after the infected configuration file had maliciously set an altered PATH, and after clearenv had wiped that variable from the environment.)

Further reading

  • Theo de Raadt et al. (2014-11-01). OpenBSD 5.6 Changelog. OpenBSD.
  • Jonathan de Boyne Pollard (2018). "read-conf". Manual. nosh toolset. Softwares.
  • Jonathan de Boyne Pollard (2018). "clearenv". Manual. nosh toolset. Softwares.
  • Jonathan de Boyne Pollard (2018). "setenv". Manual. nosh toolset. Softwares.
  • Jonathan de Boyne Pollard (2018). "printenv". Manual. nosh toolset. Softwares.

you can source the file and use var's value

. /etc/os-release
echo $ID

or try with awk

awk -F= '$1=="ID" { print $2 ;}' /etc/os-release


  • -F= tell awk to use = as separator
  • $1=="ID" filter on ID
  • { print $2 ;} print value

ID=$(grep -oP '(?<=^ID=).+' /etc/os-release | tr -d '"')
VERSION=$(grep -oP '(?<=^VERSION_ID=).+' /etc/os-release | tr -d '"')

For the explanation see the other two great answers:

  • Can grep output only specified groupings that match?
  • Shell Script - remove first and last quote (") from a variable