Как определить ОС из скрипта Bash?
Я хотел бы сохранить мой .bashrc
а также .bash_login
файлы в системе контроля версий, чтобы я мог использовать их между всеми компьютерами, которые я использую. Проблема в том, что у меня есть некоторые псевдонимы для конкретных ОС, поэтому я искал способ определить, работает ли скрипт в Mac OS X, Linux или Cygwin.
Как правильно определить операционную систему в скрипте Bash?
22 ответа
Для моего.bashrc я использую следующий код:
platform='unknown'
unamestr=`uname`
if [[ "$unamestr" == 'Linux' ]]; then
platform='linux'
elif [[ "$unamestr" == 'FreeBSD' ]]; then
platform='freebsd'
fi
Тогда я делаю что-то вроде:
if [[ $platform == 'linux' ]]; then
alias ls='ls --color=auto'
elif [[ $platform == 'freebsd' ]]; then
alias ls='ls -G'
fi
Это некрасиво, но это работает. Вы можете использовать case
вместо if
Если вы предпочитаете.
Я думаю, что следующее должно работать. Я не уверен насчет win32
хоть.
if [[ "$OSTYPE" == "linux-gnu" ]]; then
# ...
elif [[ "$OSTYPE" == "darwin"* ]]; then
# Mac OSX
elif [[ "$OSTYPE" == "cygwin" ]]; then
# POSIX compatibility layer and Linux environment emulation for Windows
elif [[ "$OSTYPE" == "msys" ]]; then
# Lightweight shell and GNU utilities compiled for Windows (part of MinGW)
elif [[ "$OSTYPE" == "win32" ]]; then
# I'm not sure this can happen.
elif [[ "$OSTYPE" == "freebsd"* ]]; then
# ...
else
# Unknown.
fi
Страница руководства bash говорит, что переменная OSTYPE хранит имя операционной системы:
OSTYPE
Автоматически устанавливается в строку, описывающую операционную систему, в которой выполняется bash. Значение по умолчанию зависит от системы.
Это установлено в linux-gnu
Вот.
Вы можете просто использовать предопределенную переменную $OSTYPE т.е.
case "$OSTYPE" in
solaris*) echo "SOLARIS" ;;
darwin*) echo "OSX" ;;
linux*) echo "LINUX" ;;
bsd*) echo "BSD" ;;
msys*) echo "WINDOWS" ;;
*) echo "unknown: $OSTYPE" ;;
esac
Другой метод заключается в обнаружении платформы на основе uname
команда.
Смотрите следующий скрипт (готов к включению в.bashrc):
# Detect the platform (similar to $OSTYPE)
OS="`uname`"
case $OS in
'Linux')
OS='Linux'
alias ls='ls --color=auto'
;;
'FreeBSD')
OS='FreeBSD'
alias ls='ls -G'
;;
'WindowsNT')
OS='Windows'
;;
'Darwin')
OS='Mac'
;;
'SunOS')
OS='Solaris'
;;
'AIX') ;;
*) ;;
esac
Определить операционную систему и тип процессора не так просто, как в переносном режиме. у меня есть sh
скрипт длиной около 100 строк, работающий на самых разных платформах Unix: любая система, которую я использовал с 1988 года.
Ключевые элементы
uname -p
тип процессора, но обычноunknown
на современных платформах Unix.uname -m
в некоторых системах Unix выдаст "имя аппаратного обеспечения"./bin/arch
, если он существует, обычно дает тип процессора.uname
без аргументов назовем операционную систему.
В конце концов вам придется подумать о различиях между платформами и о том, как хорошо вы хотите их делать. Например, чтобы все было просто, я лечу i386
через i686
, любой "Pentium*
"и любой"AMD*Athlon*
"все как x86
,
мой ~/.profile
запускает скрипт при запуске, который устанавливает одну переменную в строку, указывающую комбинацию процессора и операционной системы. У меня есть платформа для конкретной bin
, man
, lib
, а также include
каталоги, которые создаются на основе этого. Затем я установил множество переменных среды. Так, например, скрипт оболочки для переформатирования почты может вызывать, например, $LIB/mailfmt
который является платформно-исполняемым двоичным файлом.
Если вы хотите срезать углы, uname -m
и просто uname
скажу вам, что вы хотите знать на многих платформах. Добавляйте другие вещи, когда вам это нужно. (И использовать case
не вложенный if
!)
Я рекомендую использовать этот полный код Bash
lowercase(){
echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/"
}
OS=`lowercase \`uname\``
KERNEL=`uname -r`
MACH=`uname -m`
if [ "{$OS}" == "windowsnt" ]; then
OS=windows
elif [ "{$OS}" == "darwin" ]; then
OS=mac
else
OS=`uname`
if [ "${OS}" = "SunOS" ] ; then
OS=Solaris
ARCH=`uname -p`
OSSTR="${OS} ${REV}(${ARCH} `uname -v`)"
elif [ "${OS}" = "AIX" ] ; then
OSSTR="${OS} `oslevel` (`oslevel -r`)"
elif [ "${OS}" = "Linux" ] ; then
if [ -f /etc/redhat-release ] ; then
DistroBasedOn='RedHat'
DIST=`cat /etc/redhat-release |sed s/\ release.*//`
PSUEDONAME=`cat /etc/redhat-release | sed s/.*\(// | sed s/\)//`
REV=`cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//`
elif [ -f /etc/SuSE-release ] ; then
DistroBasedOn='SuSe'
PSUEDONAME=`cat /etc/SuSE-release | tr "\n" ' '| sed s/VERSION.*//`
REV=`cat /etc/SuSE-release | tr "\n" ' ' | sed s/.*=\ //`
elif [ -f /etc/mandrake-release ] ; then
DistroBasedOn='Mandrake'
PSUEDONAME=`cat /etc/mandrake-release | sed s/.*\(// | sed s/\)//`
REV=`cat /etc/mandrake-release | sed s/.*release\ // | sed s/\ .*//`
elif [ -f /etc/debian_version ] ; then
DistroBasedOn='Debian'
DIST=`cat /etc/lsb-release | grep '^DISTRIB_ID' | awk -F= '{ print $2 }'`
PSUEDONAME=`cat /etc/lsb-release | grep '^DISTRIB_CODENAME' | awk -F= '{ print $2 }'`
REV=`cat /etc/lsb-release | grep '^DISTRIB_RELEASE' | awk -F= '{ print $2 }'`
fi
if [ -f /etc/UnitedLinux-release ] ; then
DIST="${DIST}[`cat /etc/UnitedLinux-release | tr "\n" ' ' | sed s/VERSION.*//`]"
fi
OS=`lowercase $OS`
DistroBasedOn=`lowercase $DistroBasedOn`
readonly OS
readonly DIST
readonly DistroBasedOn
readonly PSUEDONAME
readonly REV
readonly KERNEL
readonly MACH
fi
fi
другие примеры примеров здесь: https://github.com/coto/server-easy-install/blob/master/lib/core.sh
Я бы предложил избежать некоторых из этих ответов. Не забывайте, что вы можете выбрать другие формы сравнения строк, которые бы прояснили большинство вариантов или ужасный код.
Одним из таких решений будет простая проверка, такая как:
if [[ "$OSTYPE" =~ ^darwin ]]; then
Который имеет дополнительное преимущество соответствия любой версии Darwin, несмотря на то, что это суффикс версии. Это также работает для любых вариантов Linux
можно ожидать.
Вы можете увидеть некоторые дополнительные примеры в моих точечных файлах здесь
Это то, что я использую, если кто-то также заинтересован в обнаружении WSL и WSL версии 2.
#!/usr/bin/env bash
unameOut=$(uname -a)
case "${unameOut}" in
*Microsoft*) OS="WSL";; #must be first since Windows subsystem for linux will have Linux in the name too
*microsoft*) OS="WSL2";; #WARNING: My v2 uses ubuntu 20.4 at the moment slightly different name may not always work
Linux*) OS="Linux";;
Darwin*) OS="Mac";;
CYGWIN*) OS="Cygwin";;
MINGW*) OS="Windows";;
*Msys) OS="Windows";;
*) OS="UNKNOWN:${unameOut}"
esac
echo ${OS};
Попробуйте использовать "uname". Например, в Linux: "uname -a".
Согласно странице руководства, uname соответствует SVr4 и POSIX, поэтому он должен быть доступен и в Mac OS X и Cygwin, но я не могу это подтвердить.
Кстати: $OSTYPE также установлен в linux-gnu
Вот:)
Ниже приведен подход к обнаружению ОС Linux на основе Debian и RedHat с использованием /etc/lsb-release и / etc / os-release (в зависимости от используемого вами варианта Linux) и выполнения простых действий на его основе.
#!/bin/bash
set -e
YUM_PACKAGE_NAME="python python-devl python-pip openssl-devel"
DEB_PACKAGE_NAME="python2.7 python-dev python-pip libssl-dev"
if cat /etc/*release | grep ^NAME | grep CentOS; then
echo "==============================================="
echo "Installing packages $YUM_PACKAGE_NAME on CentOS"
echo "==============================================="
yum install -y $YUM_PACKAGE_NAME
elif cat /etc/*release | grep ^NAME | grep Red; then
echo "==============================================="
echo "Installing packages $YUM_PACKAGE_NAME on RedHat"
echo "==============================================="
yum install -y $YUM_PACKAGE_NAME
elif cat /etc/*release | grep ^NAME | grep Fedora; then
echo "================================================"
echo "Installing packages $YUM_PACKAGE_NAME on Fedorea"
echo "================================================"
yum install -y $YUM_PACKAGE_NAME
elif cat /etc/*release | grep ^NAME | grep Ubuntu; then
echo "==============================================="
echo "Installing packages $DEB_PACKAGE_NAME on Ubuntu"
echo "==============================================="
apt-get update
apt-get install -y $DEB_PACKAGE_NAME
elif cat /etc/*release | grep ^NAME | grep Debian ; then
echo "==============================================="
echo "Installing packages $DEB_PACKAGE_NAME on Debian"
echo "==============================================="
apt-get update
apt-get install -y $DEB_PACKAGE_NAME
elif cat /etc/*release | grep ^NAME | grep Mint ; then
echo "============================================="
echo "Installing packages $DEB_PACKAGE_NAME on Mint"
echo "============================================="
apt-get update
apt-get install -y $DEB_PACKAGE_NAME
elif cat /etc/*release | grep ^NAME | grep Knoppix ; then
echo "================================================="
echo "Installing packages $DEB_PACKAGE_NAME on Kanoppix"
echo "================================================="
apt-get update
apt-get install -y $DEB_PACKAGE_NAME
else
echo "OS NOT DETECTED, couldn't install package $PACKAGE"
exit 1;
fi
exit 0
Пример вывода для Ubuntu Linux:
delivery@delivery-E5450$ sudo sh detect_os.sh
[sudo] password for delivery:
NAME="Ubuntu"
===============================================
Installing packages python2.7 python-dev python-pip libssl-dev on Ubuntu
===============================================
Ign http://dl.google.com stable InRelease
Get:1 http://dl.google.com stable Release.gpg [916 B]
Get:2 http://dl.google.com stable Release [1.189 B]
...
В bash используйте $OSTYPE
а также $HOSTTYPE
, как задокументировано; вот что я делаю. Если этого недостаточно, и если даже uname
или же uname -a
(или другие соответствующие параметры) не дают достаточно информации, всегда есть скрипт config.guess из проекта GNU, созданный именно для этой цели.
Я написал эти сахара в моем .bashrc
:
if_os () { [[ $OSTYPE == *$1* ]]; }
if_nix () {
case "$OSTYPE" in
*linux*|*hurd*|*msys*|*cygwin*|*sua*|*interix*) sys="gnu";;
*bsd*|*darwin*) sys="bsd";;
*sunos*|*solaris*|*indiana*|*illumos*|*smartos*) sys="sun";;
esac
[[ "${sys}" == "$1" ]];
}
Так что я могу делать такие вещи, как:
if_nix gnu && alias ls='ls --color=auto' && export LS_COLORS="..."
if_nix bsd && export CLICOLORS=on && export LSCOLORS="..."
if_os linux && alias psg="ps -FA | grep" #alternative to pgrep
if_nix bsd && alias psg="ps -alwx | grep -i" #alternative to pgrep
if_os darwin && alias finder="open -R"
Вы можете использовать следующее:
OS=$(uname -s)
тогда вы можете использовать переменную ОС в вашем скрипте.
Попробуй это:
DISTRO=$(cat /etc/*-release | grep -w NAME | cut -d= -f2 | tr -d '"')
echo "Determined platform: $DISTRO"
Я написал личную библиотеку Bash и среду сценариев, которая использует GNU shtool для довольно точного определения платформы.
GNU shtool - это очень переносимый набор скриптов, который содержит, среди прочего, команду "shtool platform". Вот вывод:
shtool platform -v -F "%sc (%ac) %st (%at) %sp (%ap)"
на нескольких разных машинах:
Mac OS X Leopard:
4.4BSD/Mach3.0 (iX86) Apple Darwin 9.6.0 (i386) Apple Mac OS X 10.5.6 (iX86)
Ubuntu Jaunty server:
LSB (iX86) GNU/Linux 2.9/2.6 (i686) Ubuntu 9.04 (iX86)
Debian Lenny:
LSB (iX86) GNU/Linux 2.7/2.6 (i686) Debian GNU/Linux 5.0 (iX86)
Это дает довольно удовлетворительные результаты, как вы можете видеть. GNU shtool немного медленный, поэтому я на самом деле сохраняю и обновляю идентификацию платформы в файле в системе, которую вызывают мои скрипты. Это мой каркас, так что у меня работает, но ваш пробег может отличаться.
Теперь вам нужно найти способ упаковки shtool с вашими скриптами, но это не сложное упражнение. Вы также всегда можете воспользоваться выводом uname.
РЕДАКТИРОВАТЬ:
Я пропустил пост Тедди о config.guess
(Как-то). Это очень похожие сценарии, но не одинаковые. Лично я использую shtool и для других целей, и он работал довольно хорошо для меня.
Это должно быть безопасно для использования на всех дистрибутивах.
$ cat /etc/*release
Это производит что-то вроде этого.
DISTRIB_ID=LinuxMint
DISTRIB_RELEASE=17
DISTRIB_CODENAME=qiana
DISTRIB_DESCRIPTION="Linux Mint 17 Qiana"
NAME="Ubuntu"
VERSION="14.04.1 LTS, Trusty Tahr"
ID=ubuntu
ID_LIKE=debian
PRETTY_NAME="Ubuntu 14.04.1 LTS"
VERSION_ID="14.04"
HOME_URL="http://www.ubuntu.com/"
SUPPORT_URL="http://help.ubuntu.com/"
BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
Извлечь / присвоить переменным, как вы хотите
Примечание: на некоторых установках. Это также может дать вам некоторые ошибки, которые вы можете игнорировать.
cat: /etc/upstream-release: Is a directory
Вы можете использовать следующее условие if и расширить его при необходимости:
if [ "${OSTYPE//[0-9.]/}" == "darwin" ]
then
aminute_ago="-v-1M"
elif [ "${OSTYPE//[0-9.]/}" == "linux-gnu" ]
then
aminute_ago="-d \"1 minute ago\""
fi
Это проверяет кучу known
файлы для идентификации, если дистрибутивом Linux является Debian или Ubunu, то по умолчанию используется $OSTYPE
переменная.
os='Uknown'
unamestr="${OSTYPE//[0-9.]/}"
os=$( compgen -G "/etc/*release" > /dev/null && cat /etc/*release | grep ^NAME | tr -d 'NAME="' || echo "$unamestr")
echo "$os"
Я стараюсь хранить мои.bashrc и.bash_alias в общей папке, к которой имеют доступ все платформы. Вот как я побеждаю проблему в моем.bash_alias:
if [[ -f (name of share)/.bash_alias_$(uname) ]]; then
. (name of share)/.bash_alias_$(uname)
fi
И у меня есть, например,.bash_alias_Linux с:
alias ls='ls --color=auto'
Таким образом, я разделяю платформу и переносимый код, вы можете сделать то же самое для.bashrc
Я попробовал описанные выше сообщения в нескольких дистрибутивах Linux и обнаружил, что следующее работает лучше всего для меня. Это короткий, краткий и точный ответ, который также подходит для Bash в Windows.
OS=$(cat /etc/*release | grep ^NAME | tr -d 'NAME="') #$ echo $OS # Ubuntu
Выполнение следующих действий помогло правильно выполнить проверку для Ubuntu:
if [[ "$OSTYPE" =~ ^linux ]]; then
sudo apt-get install <some-package>
fi