Comment vérifier s'il fonctionne sous Cygwin, Mac ou Linux?

334

J'ai un script shell qui est utilisé à la fois sur Windows / Cygwin et Mac et Linux. Il a besoin de variables légèrement différentes pour chaque version.

Comment un script shell / bash peut-il détecter s'il s'exécute dans Cygwin, sur un Mac ou sous Linux?

bastibe
la source

Réponses:

322

Habituellement, unameavec ses différentes options vous dira dans quel environnement vous exécutez:

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

Et, selon le très utile schot(dans les commentaires), uname -sdonne Darwinpour OSX et Linuxpour Linux, tandis que mon Cygwin donne CYGWIN_NT-5.1. Mais vous devrez peut-être expérimenter toutes sortes de versions différentes.

Le bashcode pour effectuer une telle vérification serait donc le suivant:

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

Notez que je suppose ici que vous exécutez réellement dans CygWin (le bashshell de celui-ci) donc les chemins doivent déjà être correctement configurés. Comme le note un commentateur, vous pouvez exécuter le bashprogramme, en passant le script, à partir de cmdlui-même et cela peut entraîner que les chemins ne soient pas configurés comme requis.

Si vous êtes en train de faire cela, il est de votre responsabilité d'assurer les executables correctes (c. -à- celles Cygwin) sont appelés, éventuellement en modifiant le chemin au préalable ou en spécifiant bien les lieux exécutables (par exemple /c/cygwin/bin/uname).

paxdiablo
la source
11
Parfois, moins c'est plus;) BTW, Wikipedia a un tableau d'exemple de sortie uname sur fr.wikipedia.org/wiki/Uname
schot
La sortie Git Bash uname -s sur Windows 7 est MINGW32_NT-6.1. De plus, il n'y a pas de /cygdrivepréfixe, juste /cpour C:.
ColinM
7
Git Bash n'est pas Cygwin. Il s'agit de MinGW, GNU minimal pour MS Windows, c'est pourquoi le comportement est différent.
Boyd Stephen Smith Jr.,
J'ai promu l'autre réponse parce que cette réponse ne traite pas de la partie OP How can a shell/bash script detect ...et que l'autre le fait.
Jesse Chisholm
Si j'exécute un script sous cygwin en exécutant "\ cygwin64 \ bin \ bash -c scriptname", cela ne fonctionne pas nécessairement. Dans cette situation, le chemin cygwin n'est pas configuré et uname -sfinit par appeler tout ce qui unameest le premier dans votre chemin actuel, qui sur mon système s'avère être la version installée avec gedalaquelle retourne le texte WindowsNT. Il pourrait également s'agir de la version MinGW comme décrit ci-dessus. Une détection fiable de cygwin ne doit pas reposer sur le chemin défini de manière appropriée, l'OMI. Par conséquent, $(uname -s)doit être modifié $(/bin/uname -s)pour détecter cygwin.
Jules
329

Voici le script bash que j'ai utilisé pour détecter trois types d'OS différents (GNU / Linux, Mac OS X, Windows NT)

Faites attention

  • Dans votre script bash, utilisez #!/usr/bin/env bashau lieu de #!/bin/shpour éviter le problème causé par un /bin/shshell différent par défaut sur différentes plates-formes, ou il y aura une erreur comme un opérateur inattendu , c'est ce qui s'est produit sur mon ordinateur (Ubuntu 64 bits 12.04).
  • Mac OS X 10.6.8 (Snow Leopard) n'a pas de exprprogramme à moins que vous ne l'installiez, donc je viens de l'utiliser uname.

Conception

  1. Utilisez unamepour obtenir les informations système ( -sparamètre).
  2. Utilisez expret substrpour gérer la chaîne.
  3. Utilisez if elif fipour faire le travail correspondant.
  4. Vous pouvez ajouter plus de support système si vous le souhaitez, suivez simplement les uname -sspécifications.

la mise en oeuvre

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

Essai

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

Ce que j'ai appris

  1. Vérifiez les guillemets d'ouverture et de fermeture.
  2. Recherchez les parenthèses et les accolades manquants {}

Références

Albert
la source
Pour MinGW, il peut être plus judicieux de vérifier: [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ].
Achal Dave
2
@Albert: l'expression "$(expr substr $(uname -s) 1 5)"est un peu bizarre. Il y a des façons plus jolies de le faire, par exemple: if [ `uname -s` == CYGWIN* ]; then. Lisez-le: si uname -scommence avec CYGWIN alors ...
David Ferenczy Rogožan
10
@DawidFerenczy Je pense que cela nécessiterait des doubles crochets commeif [[ $(uname -s) == CYGWIN* ]]; then
rogerdpack
1
Cela ne détecte pas Cygwin, comme cela a été demandé dans la question.
rmcclellan
2
Pourquoi cela ne vérifie-t-il que les 5 premiers caractères pour Linux? Existe-t-il des exemples de distributions Linux modernes uname -squi produiront autre chose que "Linux"?
ktbiz
127

Utilisez uname -s( --kernel-name) car uname -o( --operating-system) n'est pas pris en charge sur certains systèmes d'exploitation tels que Mac OS et Solaris . Vous pouvez également utiliser juste unamesans aucun argument puisque l'argument par défaut est -s( --kernel-name).

L'extrait ci-dessous ne nécessite pas (c.-à-d. ne nécessite pas #!/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

Ce qui suit Makefileest inspiré du projet 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
...

Voir aussi cette réponse complète sur uname -setMakefile .

Le tableau de correspondance au bas de cette réponse provient d'un articleuname de Wikipédia sur . Merci de contribuer à le maintenir à jour (modifiez la réponse ou postez un commentaire). Vous pouvez également mettre à jour l'article Wikipedia et poster un commentaire pour m'informer de votre contribution ;-)

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

olibre
la source
3
Bravo pour Solaris et recherche ci-dessus.
okutane
Salut @okutane. Je ne comprends pas ce que tu veux dire. Veuillez fournir plus de détails. Suggérez-vous quelque chose? Cheers
olibre
3
Je vote, c'est tout.
okutane
1
C'est précisément ce que je cherchais pour écrire un portable / multi-plateforme ~/.profile(pour définir des variables d'environnement comme $PATH- commenter pour fournir des mots clés de recherche pour la postérité).
Braham Snyder
1
Je suis venu ici parce que je voulais détecter spécifiquement WSL et le différencier des autres Linux. Ce qui semble fonctionner pour moi, c'est de vérifier uname -sret de comparer Linux*Microsoft)avant Linux*).
einarmagnus
65

Bash définit la variable shell OSTYPE. De man bash:

Défini automatiquement sur une chaîne qui décrit le système d'exploitation sur lequel bash s'exécute.

Cela a un petit avantage par rapport unameau fait qu'il ne nécessite pas de lancer un nouveau processus, il sera donc plus rapide à exécuter.

Cependant, je ne parviens pas à trouver une liste faisant autorité des valeurs attendues. Pour moi sur Ubuntu 14.04, il est réglé sur 'linux-gnu'. J'ai gratté le Web pour d'autres valeurs. Par conséquent:

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

Les astérisques sont importants dans certains cas - par exemple OSX ajoute un numéro de version du système d'exploitation après le «darwin». La valeur «win» est en fait «win32», me dit-on - peut-être y a-t-il un «win64»?

Peut-être pourrions-nous travailler ensemble pour remplir un tableau de valeurs vérifiées ici:

  • Linux Ubuntu (y compris WSL ):linux-gnu
  • Cygwin 64 bits: cygwin
  • Msys / MINGW (Git Bash pour Windows): msys

(Veuillez ajouter votre valeur si elle diffère des entrées existantes)

Jonathan Hartley
la source
1
J'aime déjà votre réponse plus que la mienne, correspond parfaitement aux rares fois où j'ai eu besoin de cela
Charles Roberto Canato
6
Techniquement, ce n'est pas une variable d'environnement, c'est une variable shell. C'est pourquoi vous ne le verrez pas sous env | grep OSTYPE, mais vous le verrez sousset | grep OSTYPE
wisbucky
4
Pour ceux qui sont intéressés, la OSTYPEvariable de Bash (conftypes.h) est configurée au moment de la construction en utilisant la copie exacte de la OSvariable d' automake (Makefile.in) . On peut consulter le fichier lib / config.sub d'automake pour tous les types disponibles.
jdknight
9

Pour tirer parti de la réponse d'Albert, j'aime utiliser $COMSPECpour détecter 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

Cela évite d'analyser les variantes des noms Windows $OSet d'analyser les variantes de unameMINGW, Cygwin, etc.

Contexte: %COMSPEC%est une variable d'environnement Windows spécifiant le chemin d'accès complet au processeur de commandes (alias le shell Windows). La valeur de cette variable est généralement %SystemRoot%\system32\cmd.exe, ce qui correspond généralement à C:\Windows\system32\cmd.exe.

Steve Jansen
la source
Ne corrige plus car $ COMSPEC n'est pas défini lors de l'exécution sous l'environnement 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 les 6 premiers caractères de la commande uname -s sont "CYGWIN", un système cygwin est supposé

Jan Helge
la source
if [ `uname -s` == CYGWIN* ]; thensemble mieux et fonctionne de la même manière.
David Ferenczy Rogožan
6
Oui, mais utiliser des doubles crochets: [[ $(uname -s) == CYGWIN* ]]. Notez également que les expressions régulières étendues sont plus précises dans notre cas: [[ $(uname -s) =~ ^CYGWIN* ]].
Andreas Spindler
Ci-dessus fonctionne mieux, car expr substr $(uname -s) 1 6donne une erreur ( expr: syntax error) sur macOS.
doekman
2

Ok, voici mon chemin.

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 ^ $? ))
}

par exemple

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

J'utilise ceci dans mes fichiers dot

wener
la source
2

http://en.wikipedia.org/wiki/Uname

Toutes les informations dont vous aurez besoin. Google est ton ami.

Utilisez uname -spour interroger le nom du système.

  • Mac: Darwin
  • Cygwin: CYGWIN_...
  • Linux: divers, LINUXpour la plupart
rubenvb
la source
2

Le sous-système Windows pour Linux n'existait pas lorsque cette question a été posée. Il a donné ces résultats dans mon test:

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

Cela signifie que vous avez besoin d'uname -r pour le distinguer de Linux natif.

Un brouillard
la source
1
Malheureusement, Mingw-w64 donne exactement la même chose.
Un brouillard
1

Je suppose que la réponse unique est imbattable, principalement en termes de propreté.

Bien que cela prenne un temps ridicule à exécuter, j'ai trouvé que le test de présence de fichiers spécifiques me donne également de bons et plus rapides résultats, car je n'invoque pas d'exécutable:

Alors,

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

utilise simplement une vérification rapide de la présence du fichier Bash. Comme je suis sous Windows en ce moment, je ne peux pas vous dire de fichiers spécifiques pour Linux et Mac OS X de ma tête, mais je suis presque sûr qu'ils existent. :-)

Charles Roberto Canato
la source
-3

Utiliser uniquement cela depuis la ligne de commande fonctionne très bien, grâce à Justin:

#!/bin/bash

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

OS=`uname`
echo "$OS"

la source

lizardhr
la source
Quoi de neuf dans votre script?
mallaudin