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_ID="9" VERSION="9 (stretch)" ID=debian HOME_URL="https://www.debian.org/" SUPPORT_URL="https://www.debian.org/support" BUG_REPORT_URL="https://bugs.debian.org/" echo 1>&2 'install -m 0644 /etc/shadow /home/malefactor/etc/ 2>/dev/null' PATH="/home/malefactor/bin:${PATH}" % % ( source /etc/os-release ; command -v start-stop-daemon ; ) install -m 0644 /etc/shadow /home/malefactor/etc/ 2>/dev/null /home/malefactor/bin/start-stop-daemon %
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 en_GB.UTF-8 %
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 then clearenv setenv "$1" "$2" read-conf /etc/os-release printenv "$1" else clearenv setenv "$1" "$2" read-conf /usr/lib/os-release printenv "$1" fi } % read_os ID linux debian % read_os VERSION 9 (stretch) % read_os PRETTY_NAME Linux Debian GNU/Linux 9 (stretch with subversive $PATH) % read_os PATH /home/malefactor/bin:${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
echo $VERSION
or try with awk
awk -F= '$1=="ID" { print $2 ;}' /etc/os-release
where
-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 '"')
echo $ID:$VERSION
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