¿Cómo verificar si se ejecuta en Cygwin, Mac o Linux?


334

Tengo un script de shell que se usa tanto en Windows / Cygwin como en Mac y Linux. Necesita variables ligeramente diferentes para cada versión.

¿Cómo puede un script shell / bash detectar si se está ejecutando en Cygwin, en una Mac o en Linux?

Respuestas:


322

Por lo general, unamecon sus diversas opciones le dirá en qué entorno se está ejecutando:

pax> uname -a
CYGWIN_NT-5.1 IBM-L3F3936 1.5.25(0.156/4/2) 2008-06-12 19:34 i686 Cygwin

pax> uname -s
CYGWIN_NT-5.1

Y, de acuerdo con lo muy útil schot(en los comentarios), uname -sda Darwinpara OSX y Linuxpara Linux, mientras que mi Cygwin da CYGWIN_NT-5.1. Pero es posible que tenga que experimentar con todo tipo de versiones diferentes.

Entonces, el bashcódigo para hacer tal verificación estaría en la línea de:

unameOut="$(uname -s)"
case "${unameOut}" in
    Linux*)     machine=Linux;;
    Darwin*)    machine=Mac;;
    CYGWIN*)    machine=Cygwin;;
    MINGW*)     machine=MinGw;;
    *)          machine="UNKNOWN:${unameOut}"
esac
echo ${machine}

Tenga en cuenta que estoy asumiendo aquí que en realidad está ejecutando dentro de CygWin (el bashcaparazón), por lo que las rutas ya deberían estar configuradas correctamente. Como señala un comentarista, puede ejecutar el bashprograma, pasando el script, por cmdsí mismo y esto puede provocar que las rutas no se configuren según sea necesario.

Si usted está haciendo eso, es su responsabilidad de asegurar las correctas ejecutables (es decir, los CygWin) están siendo llamados, posiblemente mediante la modificación de la ruta de antemano o especificando en detalle los sitios ejecutables (por ejemplo, /c/cygwin/bin/uname).


11
A veces menos es más;) Por cierto, Wikipedia tiene una tabla de salida de ejemplo uname en en.wikipedia.org/wiki/Uname
schot

La salida de Git Bash uname -s en Windows 7 es MINGW32_NT-6.1. Además, no hay /cygdriveprefijo, solo /cpara C:.
ColinM

77
Git Bash no es Cygwin. Es MinGW, GNU mínimo para MS Windows, por lo que el comportamiento es diferente.
Boyd Stephen Smith Jr.

Promoví la otra respuesta porque esta respuesta no se ocupa de la parte OP How can a shell/bash script detect ...y la otra sí.
Jesse Chisholm

Si ejecuto un script en cygwin ejecutando "\ cygwin64 \ bin \ bash -c scriptname", esto no necesariamente funciona. En esta situación, la ruta cygwin no se configura y uname -stermina llamando a lo que sea unameprimero en su ruta actual, que en mi sistema resulta ser la versión instalada con la gedaque devuelve el texto WindowsNT. Sin embargo, también podría ser la versión MinGW como se describió anteriormente. Una detección confiable para cygwin no debe depender de que la ruta se establezca adecuadamente, IMO. Por lo tanto, $(uname -s)debe cambiarse $(/bin/uname -s)para detectar cygwin.
Jules

329

Aquí está el script bash que utilicé para detectar tres tipos diferentes de SO (GNU / Linux, Mac OS X, Windows NT)

Presta atención

  • En su script bash, use en #!/usr/bin/env bashlugar de #!/bin/shevitar el problema causado por el /bin/shenlace a un shell predeterminado diferente en diferentes plataformas, o habrá un error como operador inesperado , eso es lo que sucedió en mi computadora (Ubuntu 64 bits 12.04).
  • Mac OS X 10.6.8 (Snow Leopard) no tiene un exprprograma a menos que lo instales, así que solo lo uso uname.

Diseño

  1. Use unamepara obtener la información del sistema ( -sparámetro).
  2. Use expry substrpara lidiar con la cuerda.
  3. Úselo if elif fipara hacer el trabajo correspondiente.
  4. Puede agregar más soporte del sistema si lo desea, solo siga las uname -sespecificaciones.

Implementación

#!/usr/bin/env bash

if [ "$(uname)" == "Darwin" ]; then
    # Do something under Mac OS X platform        
elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]; then
    # Do something under GNU/Linux platform
elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]; then
    # Do something under 32 bits Windows NT platform
elif [ "$(expr substr $(uname -s) 1 10)" == "MINGW64_NT" ]; then
    # Do something under 64 bits Windows NT platform
fi

Pruebas

  • Linux (Ubuntu 12.04 LTS, Kernel 3.2.0) probó OK.
  • OS X (10.6.8 Snow Leopard) probó OK.
  • Windows (Windows 7 de 64 bits) probó OK.

Que aprendí

  1. Verifique las cotizaciones de apertura y cierre.
  2. Compruebe si faltan paréntesis y llaves {}

Referencias


Para MinGW, puede tener más sentido para comprobar: [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ].
Achal Dave

2
@ Albert: la expresión "$(expr substr $(uname -s) 1 5)"es un poco extraña. Hay formas más bonitas de hacerlo, por ejemplo: if [ `uname -s` == CYGWIN* ]; then. Léalo: si uname -scomienza con CYGWIN entonces ...
David Ferenczy Rogožan

10
@DawidFerenczy Creo que requeriría corchetes dobles comoif [[ $(uname -s) == CYGWIN* ]]; then
rogerdpack el

1
Esto no detecta a Cygwin, como se hizo en la pregunta.
rmcclellan

2
¿Por qué esto verifica solo los primeros 5 caracteres para Linux? ¿Hay ejemplos de distribuciones modernas de Linux donde uname -sse obtenga algo diferente a "Linux"?
ktbiz

127

Use uname -s( --kernel-name) porque uname -o( --operating-system) no es compatible con algunos sistemas operativos como Mac OS y Solaris . También puede usarlo unamesin ningún argumento, ya que el argumento predeterminado es -s( --kernel-name).

El siguiente fragmento no requiere (es decir, no requiere #!/bin/bash)

#!/bin/sh

case "$(uname -s)" in

   Darwin)
     echo 'Mac OS X'
     ;;

   Linux)
     echo 'Linux'
     ;;

   CYGWIN*|MINGW32*|MSYS*|MINGW*)
     echo 'MS Windows'
     ;;

   # Add here more strings to compare
   # See correspondence table at the bottom of this answer

   *)
     echo 'Other OS' 
     ;;
esac

Lo siguiente Makefileestá inspirado en el proyecto Git ( config.mak.uname) .

ifdef MSVC     # Avoid the MingW/Cygwin sections
    uname_S := Windows
else                          # If uname not available => 'not' 
    uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
endif

# Avoid nesting "if .. else if .. else .. endif endif"
# because maintenance of matching if/else/endif is a pain

ifeq ($(uname_S),Windows)
    CC := cl 
endif
ifeq ($(uname_S),OSF1)
    CFLAGS += -D_OSF_SOURCE
endif
ifeq ($(uname_S),Linux)
    CFLAGS += -DNDEBUG
endif
ifeq ($(uname_S),GNU/kFreeBSD)
    CFLAGS += -D_BSD_ALLOC
endif
ifeq ($(uname_S),UnixWare)
    CFLAGS += -Wextra
endif
...

Vea también esta respuesta completa sobre uname -syMakefile .

La tabla de correspondencia en la parte inferior de esta respuesta es del artículo de Wikipedia sobreuname . Contribuya a mantenerlo actualizado (edite la respuesta o publique un comentario). También puede actualizar el artículo de Wikipedia y publicar un comentario para notificarme sobre su contribución ;-)

Operating System uname -s
Mac OS X Darwin
Cygwin 32-bit (Win-XP) CYGWIN_NT-5.1
Cygwin 32-bit (Win-7 32-bit)CYGWIN_NT-6.1
Cygwin 32-bit (Win-7 64-bit)CYGWIN_NT-6.1-WOW64
Cygwin 64-bit (Win-7 64-bit)CYGWIN_NT-6.1
MinGW (Windows 7 32-bit) MINGW32_NT-6.1
MinGW (Windows 10 64-bit) MINGW64_NT-10.0
Interix (Services for UNIX) Interix
MSYS MSYS_NT-6.1
MSYS2 MSYS_NT-10.0-17763
Windows Subsystem for Linux Linux
Android Linux
coreutils Linux
CentOS Linux
Fedora Linux
Gentoo Linux
Red Hat Linux Linux
Linux Mint Linux
openSUSE Linux
Ubuntu Linux
Unity Linux Linux
Manjaro Linux Linux
OpenWRT r40420 Linux
Debian (Linux) Linux
Debian (GNU Hurd) GNU
Debian (kFreeBSD) GNU/kFreeBSD
FreeBSD FreeBSD
NetBSD NetBSD
DragonFlyBSD DragonFly
Haiku Haiku
NonStop NONSTOP_KERNEL
QNX QNX
ReliantUNIX ReliantUNIX-Y
SINIX SINIX-Y
Tru64 OSF1
Ultrix ULTRIX
IRIX 32 bits IRIX
IRIX 64 bits IRIX64
MINIX Minix
Solaris SunOS
UWIN (64-bit Windows 7) UWIN-W7
SYS$UNIX:SH on OpenVMS IS/WB
z/OS USS OS/390
Cray sn5176
(SCO) OpenServer SCO_SV
(SCO) System V SCO_SV
(SCO) UnixWare UnixWare
IBM AIX AIX
IBM i with QSH OS400
HP-UX HP-UX


3
Pulgares arriba para Solaris y la investigación anterior.
Okutane

Hola @okutane No entiendo lo que quieres decir. Por favor proporcione más detalles. ¿Sugieres algo? Saludos
olibre

3
Estoy votando, eso es todo.
Okutane

1
Esto es precisamente lo que estaba buscando para escribir una plataforma portátil / multiplataforma ~/.profile(para establecer variables de entorno como $PATH: comentar para proporcionar palabras clave de búsqueda para la posteridad).
Braham Snyder

1
Vine aquí porque quería detectar WSL específicamente y diferenciarlo de otros Linux. Lo que parece funcionar para mí es verificar uname -sry comparar Linux*Microsoft)antes Linux*).
Einarmagnus

65

Bash establece la variable de shell OSTYPE. De man bash:

Se configura automáticamente en una cadena que describe el sistema operativo en el que se ejecuta bash.

Esto tiene una pequeña ventaja, unameya que no requiere el lanzamiento de un nuevo proceso, por lo que será más rápido de ejecutar.

Sin embargo, no puedo encontrar una lista autorizada de valores esperados. Para mí en Ubuntu 14.04 está configurado en 'linux-gnu'. He raspado la web en busca de otros valores. Por lo tanto:

case "$OSTYPE" in
  linux*)   echo "Linux / WSL" ;;
  darwin*)  echo "Mac OS" ;; 
  win*)     echo "Windows" ;;
  msys*)    echo "MSYS / MinGW / Git Bash" ;;
  cygwin*)  echo "Cygwin" ;;
  bsd*)     echo "BSD" ;;
  solaris*) echo "Solaris" ;;
  *)        echo "unknown: $OSTYPE" ;;
esac

Los asteriscos son importantes en algunos casos; por ejemplo, OSX agrega un número de versión del sistema operativo después del 'darwin'. Me han dicho que el valor 'ganar' es en realidad 'win32', ¿tal vez haya un 'win64'?

Quizás podríamos trabajar juntos para completar una tabla de valores verificados aquí:

  • Linux Ubuntu (incluido WSL ):linux-gnu
  • Cygwin de 64 bits: cygwin
  • Msys / MINGW (Git Bash para Windows): msys

(Agregue su valor si difiere de las entradas existentes)


1
Ya me gusta tu respuesta más que la mía, encaja perfectamente en las raras veces que he necesitado esto
Charles Roberto Canato,

66
Técnicamente, no es una variable de entorno, es una variable de shell. Es por eso que no lo verá debajo env | grep OSTYPE, pero lo verá debajoset | grep OSTYPE
wisbucky

44
Para aquellos interesados, la OSTYPEvariable de Bash (conftypes.h) se configura en tiempo de compilación utilizando la copia exacta de la OSvariable de automake (Makefile.in) . Se puede consultar el archivo lib / config.sub de automake para ver todos los tipos disponibles.
jdknight

9

Para construir sobre la respuesta de Albert, me gusta usar $COMSPECpara detectar Windows:

#!/bin/bash

if [ "$(uname)" == "Darwin" ]
then
 echo Do something under Mac OS X platform
elif [ "$(expr substr $(uname -s) 1 5)" == "Linux" ]
then
  echo Do something under Linux platform
elif [ -n "$COMSPEC" -a -x "$COMSPEC" ]
then 
  echo $0: this script does not support Windows \:\(
fi

Esto evita las variantes de análisis de nombres de Windows $OSy las variantes de análisis unamecomo MINGW, Cygwin, etc.

Antecedentes: %COMSPEC%es una variable de entorno de Windows que especifica la ruta completa al procesador de comandos (también conocido como el shell de Windows). El valor de esta variable es típicamente %SystemRoot%\system32\cmd.exe, que generalmente se evalúa C:\Windows\system32\cmd.exe.


No es correcto ya que $ COMSPEC no está configurado cuando se ejecuta en el entorno Windows UWS Bash.
Julian Knight

9
# This script fragment emits Cygwin rulez under bash/cygwin
if [[ $(uname -s) == CYGWIN* ]];then
    echo Cygwin rulez
else 
    echo Unix is king
fi

Si los 6 primeros caracteres del comando uname -s son "CYGWIN", se supone un sistema cygwin


if [ `uname -s` == CYGWIN* ]; thense ve mejor y funciona igual.
David Ferenczy Rogožan

66
Sí, pero el uso de soportes dobles: [[ $(uname -s) == CYGWIN* ]]. Tenga en cuenta también que las expresiones regulares extendidas son más precisos en nuestro caso: [[ $(uname -s) =~ ^CYGWIN* ]].
Andreas Spindler

Lo anterior funciona mejor, porque expr substr $(uname -s) 1 6da un error ( expr: syntax error) en macOS.
doekman

2

Ok, aquí está mi camino.

osis()
{
    local n=0
    if [[ "$1" = "-n" ]]; then n=1;shift; fi

    # echo $OS|grep $1 -i >/dev/null
    uname -s |grep -i "$1" >/dev/null

    return $(( $n ^ $? ))
}

p.ej

osis Darwin &&
{
    log_debug Detect mac osx
}
osis Linux &&
{
    log_debug Detect linux
}
osis -n Cygwin &&
{
    log_debug Not Cygwin
}

Lo uso en mis archivos de puntos



2

El subsistema de Windows para Linux no existía cuando se hizo esta pregunta. Dio estos resultados en mi prueba:

uname -s -> Linux
uname -o -> GNU/Linux
uname -r -> 4.4.0-17763-Microsoft

Esto significa que necesita uname -r para distinguirlo de Linux nativo.


1
Desafortunadamente, Mingw-w64 da exactamente lo mismo.
Una niebla

1

Supongo que la respuesta única es inmejorable, principalmente en términos de limpieza.

Aunque lleva un tiempo ridículo ejecutarlo, descubrí que probar la presencia de archivos específicos también me da resultados buenos y más rápidos, ya que no estoy invocando un ejecutable:

Entonces,

[ -f /usr/bin/cygwin1.dll ] && echo Yep, Cygwin running

solo usa una comprobación rápida de presencia de archivos Bash. Como estoy en Windows en este momento, no puedo decirte ningún archivo específico para Linux y Mac OS X, pero estoy bastante seguro de que existen. :-)


-3

Use solo esto desde la línea de comandos funciona muy bien, gracias a Justin:

#!/bin/bash

################################################## #########
# Bash script to find which OS
################################################## #########

OS=`uname`
echo "$OS"

fuente


¿Qué hay de nuevo en tu guión?
mallaudin
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.