¿Cómo detectar el sistema operativo desde un script Bash?

Me gustaría mantener mis archivos .bashrc y .bash_login en control de versiones para poder usarlos entre todas las computadoras que uso. El problema es que tengo algunos alias específicos del sistema operativo, por lo que estaba buscando una manera de determinar si el script se ejecuta en Mac OS X, Linux o Cygwin .

¿Cuál es la forma correcta de detectar el sistema operativo en un script Bash ?

Para mi .bashrc, uso el siguiente código:

 platform='unknown' unamestr=`uname` if [[ "$unamestr" == 'Linux' ]]; then platform='linux' elif [[ "$unamestr" == 'FreeBSD' ]]; then platform='freebsd' fi 

Luego hago algunas cosas como:

 if [[ $platform == 'linux' ]]; then alias ls='ls --color=auto' elif [[ $platform == 'freebsd' ]]; then alias ls='ls -G' fi 

Es feo, pero funciona. Puede usar el case lugar de si lo prefiere.

La página de manual de bash dice que la variable OSTYPE almacena el nombre del sistema de operación:

OSTYPE Establecido automáticamente en una cadena que describe el sistema operativo en el que bash se está ejecutando. El valor predeterminado depende del sistema.

Está configurado para linux-gnu aquí.

Creo que lo siguiente debería funcionar. Aunque no estoy seguro acerca de 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 

Simplemente puede usar la variable $ OSTYPE predefinida, es decir:

 case "$OSTYPE" in solaris*) echo "SOLARIS" ;; darwin*) echo "OSX" ;; linux*) echo "LINUX" ;; bsd*) echo "BSD" ;; msys*) echo "WINDOWS" ;; *) echo "unknown: $OSTYPE" ;; esac 

Otro método es detectar la plataforma basada en el comando uname .

Vea la siguiente secuencia de comandos (lista para incluir en .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 

Puedes encontrar algún ejemplo práctico en mi .bashrc .

Detectar el sistema operativo y el tipo de CPU no es tan fácil de hacer de forma portátil . Tengo un script sh de aproximadamente 100 líneas que funciona en una gran variedad de plataformas Unix: cualquier sistema que haya usado desde 1988.

Los elementos clave son

  • uname -p es el tipo de procesador, pero generalmente se unknown en las plataformas modernas de Unix.

  • uname -m dará el “nombre de hardware de la máquina” en algunos sistemas Unix.

  • /bin/arch , si existe, generalmente dará el tipo de procesador.

  • uname sin argumentos nombrará el sistema operativo.

Finalmente, tendrá que pensar en las distinciones entre las plataformas y lo bien que desea hacerlas. Por ejemplo, para simplificar, trato de i386 a i686 , cualquier ” Pentium* ” y cualquier ” AMD*Athlon* “, todo como x86 .

Mi ~/.profile ejecuta un script al inicio que establece una variable en una cadena que indica la combinación de CPU y sistema operativo. Tengo bin , man , lib e include directorios específicos que se configuran en función de eso. Luego configuré una carga de variables de entorno. Por ejemplo, un script de shell para reformatear el correo puede llamar, por ejemplo, $LIB/mailfmt que es un binario ejecutable específico de la plataforma.

Si quiere cortar las esquinas , uname -m y uname llana le dirá lo que quiere saber en muchas plataformas. Agregue otras cosas cuando lo necesite. (Y case uso, no nested if !)

Recomiendo usar este código de bash completo

 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 

ejemplos más ejemplos aquí: https://github.com/coto/server-easy-install/blob/master/lib/core.sh

En bash, use $OSTYPE y $HOSTTYPE , según lo documentado; esto es lo que hago. Si eso no es suficiente, y si incluso uname o uname -a (u otras opciones apropiadas) no brindan suficiente información, siempre existe el script config.guess del proyecto GNU, hecho exactamente para este propósito.

Intenta usar “uname”. Por ejemplo, en Linux: “uname -a”.

De acuerdo con la página del manual, uname se ajusta a SVr4 y POSIX, por lo que debería estar disponible también para Mac OS X y Cygwin , pero no puedo confirmarlo.

Por cierto: $ OSTYPE también está configurado para linux-gnu aquí 🙂

Sugeriría evitar algunas de estas respuestas. No olvide que puede elegir otras formas de comparación de cadenas, lo que aclararía la mayoría de las variaciones, o el código feo ofrecido.

Una de esas soluciones sería una verificación simple, como:

if [[ "$OSTYPE" =~ ^darwin ]]; then

Lo cual tiene el beneficio adicional de emparejar cualquier versión de Darwin, a pesar de su sufijo de versión. Esto también funciona para cualquier variación de Linux uno pueda esperar.

Puedes ver algunos ejemplos adicionales dentro de mis archivos dot aquí

 uname 

o

 uname -a 

si quieres más información

Escribí una biblioteca Bash personal y un marco de scripting que usa shtool de GNU para hacer una detección de plataforma bastante precisa.

GNU shtool es un conjunto de scripts muy portátil que contiene, entre otras cosas útiles, el comando ‘shtool platform’. Aquí está la salida de:

 shtool platform -v -F "%sc (%ac) %st (%at) %sp (%ap)" 

en algunas máquinas diferentes:

 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) 

Esto produce resultados bastante satisfactorios, como puede ver. GNU shtool es un poco lento, así que realmente almaceno y actualizo la identificación de la plataforma en un archivo en el sistema al que llaman mis scripts. Es mi marco, así que eso funciona para mí, pero su kilometraje puede variar.

Ahora, tendrás que encontrar la forma de empaquetar shtool con tus scripts, pero no es un ejercicio difícil. Siempre puede recurrir a la salida de uname, también.

EDITAR:

Me perdí la publicación de Teddy sobre config.guess (de alguna manera). Estos son scripts muy similares, pero no son lo mismo. Yo personalmente uso shtool para otros usos también, y me ha funcionado bastante bien.

Escribí estos azúcares en mi .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" ]]; } 

Entonces puedo hacer cosas como estas:

 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" 

Esto debería ser seguro de usar en todas las distribuciones.

 $ cat /etc/*release 

Esto produce algo como esto.

  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/" 

Extraiga / asigne variables como lo desee

Nota: en algunas configuraciones. Esto también puede darte algunos errores que puedes ignorar.

  cat: /etc/upstream-release: Is a directory 

A continuación se muestra un enfoque para detectar el sistema operativo Linux basado en Debian y RedHat que utiliza / etc / lsb-release y / etc / os-release (dependiendo del sabor de Linux que esté utilizando) y tome una acción simple basada en él.

 #!/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 

Ejemplo de salida para 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] ... 

Puedes usar lo siguiente:

 OS=$(uname -s) 

entonces puedes usar la variable OS en tu script.

Hacer lo siguiente ayudó a realizar la comprobación correctamente para ubuntu:

 if [[ "$OSTYPE" =~ ^linux ]]; then sudo apt-get install  fi 

Tiendo a mantener mi .bashrc y .bash_alias en un recurso compartido de archivos al que todas las plataformas pueden acceder. Así es como conquisto el problema en mis .bash_alias:

 if [[ -f (name of share)/.bash_alias_$(uname) ]]; then . (name of share)/.bash_alias_$(uname) fi 

Y tengo, por ejemplo, un .bash_alias_Linux con:

 alias ls='ls --color=auto' 

De esta forma, mantengo el código portátil y específico de la plataforma por separado, puedes hacer lo mismo para .bashrc

Puede usar la siguiente cláusula if y expandirla según sea necesario:

 if [ "${OSTYPE//[0-9.]/}" == "darwin" ] then aminute_ago="-v-1M" elif [ "${OSTYPE//[0-9.]/}" == "linux-gnu" ] then aminute_ago="-d \"1 minute ago\"" fi 

Probé los mensajes anteriores en algunas distribuciones de Linux y encontré que lo siguiente funciona mejor para mí. Es una respuesta breve y concisa que también funciona para Bash en Windows.

 OS=$(cat /etc/*release | grep ^NAME | tr -d 'NAME="') #$ echo $OS # Ubuntu