¿Cómo comprobar si se está ejecutando en Cygwin, Mac o Linux?
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?
Por lo general, uname
con sus diversas opciones te indicará en qué entorno estás 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, según lo muy útil schot
(en los comentarios), uname -s
da Darwin
para OSX y Linux
para Linux, mientras que mi Cygwin da CYGWIN_NT-5.1
. Pero es posible que tengas que experimentar con todo tipo de versiones diferentes.
Entonces, el bash
código para realizar dicha verificación sería similar a:
unameOut="$(uname -s)"
case "${unameOut}" in
Linux*) machine=Linux;;
Darwin*) machine=Mac;;
CYGWIN*) machine=Cygwin;;
MINGW*) machine=MinGw;;
MSYS_NT*) machine=Git;;
*) machine="UNKNOWN:${unameOut}"
esac
echo ${machine}
Tenga en cuenta que asumo aquí que en realidad está ejecutando CygWin ( bash
su shell), por lo que las rutas ya deberían estar configuradas correctamente. Como señala un comentarista, puede ejecutar el bash
programa, pasando el script, desde cmd
sí mismo y esto puede provocar que las rutas no se configuren según sea necesario.
Si está haciendo eso, es su responsabilidad asegurarse de que se llamen los ejecutables correctos (es decir, los de CygWin), posiblemente modificando la ruta de antemano o especificando completamente las ubicaciones de los ejecutables (por ejemplo, /c/cygwin/bin/uname
).
Detecta tres tipos de sistemas operativos diferentes (GNU/Linux, Mac OS X, Windows NT)
Notas
- En su script bash, utilícelo
#!/usr/bin/env bash
en lugar de#!/bin/sh
para evitar el problema causado por/bin/sh
el vínculo a diferentes shells predeterminados 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
expr
programa a menos que lo instales, así que solo usouname
.
Diseño
- Úselo
uname
para obtener la información del sistema (-s
parámetro). - Utilice
expr
ysubstr
para lidiar con la cuerda. - Úselo
if
elif
fi
para hacer el trabajo de combinación. - Puede agregar más soporte del sistema si lo desea, simplemente siga las
uname -s
especificaciones.
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ó bien.
- OS X (10.6.8 Snow Leopard) probado correctamente.
- Windows (Windows 7 de 64 bits) se probó correctamente.
Que aprendí
- Verifique las cotizaciones de apertura y cierre.
- Compruebe si faltan paréntesis y llaves {}
Referencias
- [1] nombre - wikipedia
- [2] error de sintaxis del script de shell: final inesperado del archivo
- [3] Detectar el sistema operativo desde un script Bash
- [4] Introducción a la programación BASH
Utilice uname -s
( --kernel-name
) porque uname -o
( --operating-system
) no es compatible con algunos sistemas operativos como Mac OS y Solaris . También puede utilizar just uname
sin ningún argumento ya que el argumento predeterminado es -s
( --kernel-name
).
Para distinguir WSL de Linux, einarmagnus recomienda uname -sr
( --kernel-name --kernel-release
) como se propone en el siguiente script. 😉
#!/bin/sh
case "$(uname -sr)" in
Darwin*)
echo 'Mac OS X'
;;
Linux*Microsoft*)
echo 'WSL' # Windows Subsystem for Linux
;;
Linux*)
echo 'Linux'
;;
CYGWIN*|MINGW*|MINGW32*|MSYS*)
echo 'MS Windows'
;;
# Add here more strings to compare
# See correspondence table at the bottom of this answer
*)
echo 'Other OS'
;;
esac
Lo siguiente Makefile
está 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
...
Consulte también esta respuesta completa sobre uname -s
yMakefile
.
La tabla de correspondencia al final de esta respuesta es de un artículo de Wikipedia sobreuname
. Contribuya para mantenerlo actualizado (edite la respuesta o publique un comentario). También puedes actualizar el artículo de Wikipedia y publicar un comentario para notificarme sobre tu contribución ;-)
Sistema operativo | nombre -s |
---|---|
Mac OS X | Darwin |
Cygwin de 32 bits (Win XP) | CYGWIN_NT-5.1 |
Cygwin de 32 bits (Win-7 de 32 bits) | CYGWIN_NT-6.1 |
Cygwin de 32 bits (Win-7 de 64 bits) | CYGWIN_NT-6.1-WOW64 |
Cygwin de 64 bits (Win-7 de 64 bits) | CYGWIN_NT-6.1 |
MinGW (Windows 7 de 32 bits) | MINGW32_NT-6.1 |
MinGW (Windows 10 de 64 bits) | MINGW64_NT-10.0 |
Interix (Servicios para UNIX) | Interix |
MSYS | MSYS_NT-6.1 |
MSYS2 | MSYS_NT-10.0-17763 |
Subsistema de Windows para Linux | linux |
Androide | linux |
coreutils | linux |
CentOS | linux |
sombrero | linux |
Gentoo | linux |
Red Hat Linux | linux |
menta linux | linux |
openSUSE | linux |
ubuntu | linux |
Unidad Linux | linux |
ManjaroLinux | linux |
OpenWRT r40420 | linux |
Debian (Linux) | linux |
Debian (GNU Hurd) | ÑU |
Debian (kFreeBSD) | GNU/kFreeBSD |
FreeBSD | FreeBSD |
NetBSD | NetBSD |
OpenBSD | OpenBSD |
DragonFlyBSD | Libélula |
haikus | haikus |
Sin escalas | 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 (Windows 7 de 64 bits) | UWIN-W7 |
SYS$UNIX:SH en OpenVMS | IS/BM |
z/OS USS | OS/390 |
Cray | sn5176 |
(SCO) Servidor abierto | SCO_SV |
(SCO) Sistema V | SCO_SV |
(SCO) UnixWare | Unixware |
IBM AIX | AIX |
IBM i con QSH | OS400 |
HP-UX | HP-UX |
Bash establece la variable de shell OSTYPE. De man bash
:
Se establece automáticamente en una cadena que describe el sistema operativo en el que se ejecuta bash.
Esto tiene una pequeña ventaja sobre uname
el hecho de que no requiere iniciar 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'. Busqué en la web algunos otros valores. Por eso:
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 de "darwin". Me dijeron que el valor 'win' es en realidad 'win32'. ¿Quizás 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
- MacOS Venura:
darwin22.0
(Adjunte su valor si difiere de las entradas existentes)