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.
My first take on resolving this was to use the
#!/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
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
[[: not found issue is because
[[ is a bash operator and not supported in
dash. But easy fix to the same is replacing
] 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
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"
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
#!/bin/sh . /etc/os-release echo "Your OS is $ID"