bash - español - scripts linux ejercicios resueltos
¿Cómo detectar el sistema operativo desde un script Bash? (21)
Me gustaría mantener mis archivos .bashrc
y .bash_login
en el control de versiones para poder usarlos entre todas las computadoras que uso. El problema es que tengo algunos alias específicos del sistema operativo, así 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 de Bash ?
A continuación se muestra un enfoque para detectar el sistema operativo Linux basado en Debian y RedHat haciendo uso de la versión / etc / lsb-release y / etc / os (según el tipo de Linux que esté usando) y realice una acción simple basada en ella.
#!/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]
...
Creo que lo siguiente debería funcionar. Aunque no estoy seguro 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
Detectar el sistema operativo y el tipo de CPU no es tan fácil de hacer de manera 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 un tipo de procesador, pero generalmente esunknown
en las plataformas Unix modernas.uname -m
le dará el "nombre del 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.
Eventualmente, tendrá que pensar en las distinciones entre plataformas y qué tan bien desea hacerlas. Por ejemplo, solo para mantener las cosas simples, trato de i386
a i686
, cualquier " Pentium*
" y cualquier " AMD*Athlon*
" 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 directorios específicos de plataforma, man
, lib
e include
directorios que se configuran en función de eso. Luego configuro un barco cargado 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 desea cortar esquinas , uname -m
y plain uname
le dirán lo que desea saber en muchas plataformas. Agrega otras cosas cuando las necesites. (Y case
uso, no anidado if
!)
En bash, use $OSTYPE
y $HOSTTYPE
, como se documenta; 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 config.guess script config.guess del proyecto GNU, hecho exactamente para este propósito.
Escribí una biblioteca Bash personal y un marco de scripting que utiliza 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 ''plataforma shtool''. Aquí está la salida de:
shtool platform -v -F "%sc (%ac) %st (%at) %sp (%ap)"
en unas pocas 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 se puede ver. GNU shtool es un poco lento, por lo 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, por lo que funciona para mí, pero su kilometraje puede variar.
Ahora, tendrás que encontrar una manera de empaquetar shtool con tus scripts, pero no es un ejercicio difícil. Siempre puedes recurrir a la salida uname, también.
EDITAR:
Me perdí la publicación de Teddy sobre config.guess
(de alguna manera). Estos son scripts muy similares, pero no iguales. Personalmente uso shtool también para otros usos, 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" ]];
}
Así que puedo hacer cosas como:
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 para 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/"
Extraer / asignar a las variables como desee
Nota: En algunas configuraciones. Esto también puede darte algunos errores que puedes ignorar.
cat: /etc/upstream-release: Is a directory
Esto verifica un montón de archivos known
para identificar si la distribución de Linux es Debian o Ubunu, y por defecto es la variable $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"
Hacer lo siguiente ayudó a realizar la comprobación correctamente para ubuntu:
if [[ "$OSTYPE" =~ ^linux ]]; then
sudo apt-get install <some-package>
fi
La página de manual de bash dice que la variable OSTYPE almacena el nombre del sistema operativo:
OSTYPE
Establece automáticamente una cadena que describe el sistema operativo en el que se está ejecutando bash. El valor predeterminado es dependiente del sistema.
Se establece en linux-gnu
aquí.
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
Entonces hago 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 utilizar el case
lugar de si lo prefiere.
Probé los mensajes anteriores en algunas distribuciones de Linux y encontré que lo siguiente funciona mejor para mí. Es una respuesta de palabra exacta, breve y concisa que también funciona para Bash en Windows.
OS=$(cat /etc/*release | grep ^NAME | tr -d ''NAME="'') #$ echo $OS # Ubuntu
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
Puedes usar lo siguiente:
OS=$(uname -s)
entonces puedes usar la variable OS en tu script.
Recomiendo usar este completo código 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
más ejemplos de ejemplos aquí: https://github.com/coto/server-easy-install/blob/master/lib/core.sh
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 el siguiente script (listo 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
Tiendo a mantener mis archivos .bashrc y .bash_alias en un recurso compartido de archivos al que pueden acceder todas las plataformas. 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 manera mantengo el código de la plataforma específica y el código portátil por separado, puede hacer lo mismo para .bashrc
Trate de usar "uname". Por ejemplo, en Linux: "uname -a".
De acuerdo con la página del manual, uname cumple con SVr4 y POSIX, por lo que también debería estar disponible en Mac OS X y Cygwin , pero no puedo confirmarlo.
BTW: $ OSTYPE también se establece en linux-gnu
aquí :)
Yo sugeriría evitar algunas de estas respuestas. No olvide que puede elegir otras formas de comparación de cadenas, que aclararían la mayoría de las variaciones, o el código feo ofrecido.
Una de esas soluciones sería una simple comprobación, como:
if [[ "$OSTYPE" =~ ^darwin ]]; then
Lo que tiene el beneficio adicional de hacer coincidir cualquier versión de Darwin, a pesar de su sufijo. Esto también funciona para cualquier variación de Linux
uno pueda esperar.
Puedes ver algunos ejemplos adicionales dentro de mis dotfiles here
prueba esto:
DISTRO=$(cat /etc/*-release | grep -w NAME | cut -d= -f2 | tr -d ''"'')
echo "Determined platform: $DISTRO"
uname
o
uname -a
si quieres mas informacion