Each linux distribution uses different package manager. To be able to execute commands based on the type of OS in a shell script, we need a way to detect the OS first.
Using which
command
My first take on resolving this was to use the which
command
#!/bin/bash
if [[ `which yum` ]]; then
IS_RHEL=1
elif [[ `which apt` ]]; then
IS_UBUNTU=1
elif [[ `which apk` ]]; then
IS_ALPINE=1
else
IS_UNKNOWN=1
fi
Now this works well on most OS, but the issue is that when you use the same on docker images. Official Docker images have minimal software packages. And which
command is missing in case of the centos:7.2.1511
image
tarunlalwani@instance-1:~$ docker run -it centos:7.2.1511 bash
[root@cf78fcecc38e /]# which yum
bash: which: command not found
[root@cf78fcecc38e /]#
Now since we need to install the which command, we can either bruteforce the installation to make sure which command exists
#!/bin/bash
yum install -y which >/dev/null
And this command would run irrespective of the OS. Not a very clean approach but still works. Now let’s turn our attention to the alpine:3.5
docker image. Alpine images don’t have the bash
shell, instead it uses sh
. This means in the she bang we should use #!/bin/sh
instead of #!/bin/bash
. But this breaks our script on ubuntu:16.04
as ubuntu uses dash as its low end shell. /bin/sh
is just symlink to dash
in ubuntu.
$ if [[ `which yum` ]]; then
IS_RHEL=1
fi
sh: 1: [[: not found
The [[:
not found issue is because [[
is a bash operator and not supported in dash
. But easy fix to the same is replacing [[
and ]]
with [
and ]
respectively. The updated code is shown below
#!/bin/bash
if [ `which yum` ]; then
IS_RHEL=1
elif [ `which apt` ]; then
IS_UBUNTU=1
elif [ `which apk` ]; then
IS_ALPINE=1
else
IS_UNKNOWN=1
fi
Using more reliable /etc/os-release
After some research I found a better a more reliable way of finding the OS details. Which is by using /etc/os-release
file. Sample content for the centos:7.2.1511
docker image is below
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"
CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"
And for ubuntu:16.04
docker image
NAME="Ubuntu"
VERSION="16.04.2 LTS (Xenial Xerus)"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 16.04.2 LTS"
VERSION_ID="16.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
VERSION_CODENAME=xenial
UBUNTU_CODENAME=xenial
So we can use $ID
to identify the OS. Simply use the source
command to load the file in your script and then use $ID
for checking the OS
#!/bin/sh
source /etc/os-release
echo "Your OS is $ID"
In case of Ubuntu’s dash
you will get an error sh: 1: source: not found
. This is becase dash
doesn’t implement the bash’s source
command. The simple fix is to replace source
with .
command
#!/bin/sh
. /etc/os-release
echo "Your OS is $ID"