Wie überprüfe ich, ob es unter Cygwin, Mac oder Linux läuft?

332

Ich habe ein Shell-Skript, das sowohl unter Windows / Cygwin als auch unter Mac und Linux verwendet wird. Für jede Version sind leicht unterschiedliche Variablen erforderlich.

Wie kann ein Shell / Bash-Skript erkennen, ob es in Cygwin, auf einem Mac oder unter Linux ausgeführt wird?

Bastibe
quelle

Antworten:

321

In der Regel unameerfahren Sie anhand der verschiedenen Optionen, in welcher Umgebung Sie ausgeführt werden:

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

Und laut dem sehr hilfreichen schot(in den Kommentaren) uname -sgibt es Darwinfür OSX und Linuxfür Linux, während mein Cygwin gibt CYGWIN_NT-5.1. Möglicherweise müssen Sie jedoch mit allen möglichen Versionen experimentieren.

Der bashCode für eine solche Überprüfung lautet also wie folgt:

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

Beachten Sie, dass ich hier davon ausgehe, dass Sie tatsächlich in CygWin (der bashShell davon) ausgeführt werden, sodass Pfade bereits korrekt eingerichtet sein sollten. Wie ein Kommentator feststellt, können Sie das bashProgramm unter Übergabe des Skripts von cmdsich aus ausführen. Dies kann dazu führen, dass die Pfade nicht nach Bedarf eingerichtet werden.

Wenn Sie sind , das zu tun, ist es in Ihrer Verantwortung , die richtigen ausführbaren Dateien (dh die CygWin sind) werden genannt, die möglicherweise durch Ändern der Pfad vorher oder vollständig unter Angabe der ausführbaren Orten (zB zu gewährleisten /c/cygwin/bin/uname).

paxdiablo
quelle
11
Manchmal ist weniger mehr;) Übrigens hat Wikipedia eine Tabelle mit Beispiel-Uname-Ausgaben unter en.wikipedia.org/wiki/Uname
schot
Die Ausgabe von Git Bash uname -s unter Windows 7 lautet MINGW32_NT-6.1. Es gibt auch kein /cygdrivePräfix, nur /cfür C:.
ColinM
7
Git Bash ist nicht Cygwin. Es ist MinGW, minimale GNU für MS Windows, weshalb das Verhalten anders ist.
Boyd Stephen Smith Jr.
Ich habe die andere Antwort beworben, weil diese Antwort sich nicht mit dem OP-Teil befasst How can a shell/bash script detect ...und die andere.
Jesse Chisholm
Wenn ich ein Skript unter cygwin durch Ausführen von "\ cygwin64 \ bin \ bash -c scriptname" ausführe, funktioniert dies nicht unbedingt. In dieser Situation wird der Cygwin-Pfad nicht eingerichtet und uname -sruft schließlich das auf, was unamezuerst in Ihrem aktuellen Pfad steht. Auf meinem System stellt sich heraus, dass es sich um die installierte Version handelt, mit gedader der Text zurückgegeben wird WindowsNT. Es könnte jedoch auch die oben beschriebene MinGW-Version sein. Eine zuverlässige Erkennung für Cygwin darf nicht davon abhängen, dass der Pfad entsprechend eingestellt ist, IMO. Daher $(uname -s)sollte geändert werden $(/bin/uname -s), um Cygwin zu erkennen.
Jules
329

Hier ist das Bash-Skript, mit dem ich drei verschiedene Betriebssystemtypen erkannt habe (GNU / Linux, Mac OS X, Windows NT).

Passt auf

  • Verwenden Sie in Ihrem Bash-Skript #!/usr/bin/env bashstattdessen #!/bin/sh, um das Problem zu verhindern, das durch die /bin/shVerknüpfung mit einer anderen Standard-Shell auf verschiedenen Plattformen verursacht wird, oder es tritt ein Fehler wie ein unerwarteter Operator auf. Dies ist auf meinem Computer passiert (Ubuntu 64 Bit 12.04).
  • Mac OS X 10.6.8 (Snow Leopard) hat kein exprProgramm, es sei denn, Sie installieren es, also benutze ich es einfach uname.

Design

  1. Verwenden Sie unamediese Option , um die Systeminformationen ( -sParameter) abzurufen.
  2. Verwenden Sie exprund substr, um mit der Zeichenfolge umzugehen.
  3. Verwenden Sie if elif fidiese Option , um den passenden Job auszuführen.
  4. Sie können weitere Systemunterstützung hinzufügen, wenn Sie möchten. Befolgen Sie einfach die uname -sSpezifikation.

Implementierung

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

Testen

  • Linux (Ubuntu 12.04 LTS, Kernel 3.2.0) wurde in Ordnung getestet.
  • OS X (10.6.8 Snow Leopard) wurde in Ordnung getestet.
  • Windows (Windows 7 64 Bit) wurde auf OK getestet.

Was ich gelernt habe

  1. Überprüfen Sie, ob Anführungszeichen geöffnet oder geschlossen sind.
  2. Überprüfen Sie, ob Klammern und Klammern fehlen {}

Verweise

Albert
quelle
Für MinGW kann es sinnvoller sein, Folgendes zu überprüfen : [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ].
Achal Dave
2
@ Albert: Ausdruck "$(expr substr $(uname -s) 1 5)"ist ein bisschen komisch. Es gibt hübschere Möglichkeiten, dies zu tun, zum Beispiel : if [ `uname -s` == CYGWIN* ]; then. Lesen Sie es: Wenn uname -smit CYGWIN beginnt, dann ...
David Ferenczy Rogožan
10
@DawidFerenczy Ich glaube, es würde doppelte Klammern wieif [[ $(uname -s) == CYGWIN* ]]; then
Rogerdpack
1
Dies erkennt Cygwin nicht, wie in der Frage gestellt wurde.
Rmcclellan
2
Warum werden nur die ersten 5 Zeichen für Linux überprüft? Gibt es Beispiele für moderne Linux-Distributionen uname -s, die etwas anderes als "Linux" liefern?
Ktbiz
126

Verwenden Sie uname -s( --kernel-name), da uname -o( --operating-system) auf einigen Betriebssystemen wie Mac OS und Solaris nicht unterstützt wird . Sie können auch nur unameohne Argument verwenden, da das Standardargument -s( --kernel-name) ist.

Das folgende Snippet ist nicht erforderlich (dh nicht erforderlich #!/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

Das Folgende Makefileist vom Git-Projekt ( config.mak.uname) inspiriert .

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
...

Siehe auch diese vollständige Antwort zu uname -sundMakefile .

Die Korrespondenztabelle am Ende dieser Antwort stammt aus einem Wikipedia-Artikel überuname . Bitte tragen Sie dazu bei, es auf dem neuesten Stand zu halten (bearbeiten Sie die Antwort oder schreiben Sie einen Kommentar). Sie können auch den Wikipedia-Artikel aktualisieren und einen Kommentar veröffentlichen, um mich über Ihren Beitrag zu informieren ;-)

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
quelle
3
Daumen hoch für Solaris und Forschung oben.
Okutane
Hallo @okutane. Ich verstehe nicht was du meinst. Bitte geben Sie weitere Details an. Schlagen Sie etwas vor? Prost
olibre
3
Ich stimme ab, das war's.
Okutane
1
Dies ist genau das, wonach ich gesucht habe, um eine tragbare / plattformübergreifende ~/.profile(um Umgebungsvariablen wie $PATH- Kommentieren, um Suchschlüsselwörter für die Nachwelt bereitzustellen) zu schreiben .
Braham Snyder
1
Ich bin hierher gekommen, weil ich WSL spezifisch erkennen und von anderen Linux unterscheiden wollte. Was dann für mich zu funktionieren scheint, ist vorher zu prüfen uname -srund zu vergleichen . Linux*Microsoft)Linux*)
Einarmagnus
65

Bash setzt die Shell-Variable OSTYPE. Von man bash:

Wird automatisch auf eine Zeichenfolge festgelegt, die das Betriebssystem beschreibt, auf dem Bash ausgeführt wird.

Dies hat einen winzigen Vorteil gegenüber dem, unamedass kein neuer Prozess gestartet werden muss und daher schneller ausgeführt werden kann.

Ich kann jedoch keine maßgebliche Liste der erwarteten Werte finden. Für mich unter Ubuntu 14.04 ist es auf 'linux-gnu' eingestellt. Ich habe das Web nach anderen Werten durchsucht. Daher:

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

Die Sternchen sind in einigen Fällen wichtig - zum Beispiel fügt OSX nach dem 'darwin' eine Versionsnummer des Betriebssystems hinzu. Der 'Win'-Wert ist tatsächlich' Win32 ', wurde mir gesagt - vielleicht gibt es einen' Win64 '?

Vielleicht könnten wir hier zusammenarbeiten, um eine Tabelle mit verifizierten Werten zu füllen:

  • Linux Ubuntu (inkl. WSL ):linux-gnu
  • Cygwin 64-Bit: cygwin
  • Msys / MINGW (Git Bash für Windows): msys

(Bitte fügen Sie Ihren Wert hinzu, wenn er von vorhandenen Einträgen abweicht.)

Jonathan Hartley
quelle
1
Ich mag Ihre Antwort bereits mehr als meine, passt perfekt zu den seltenen Zeiten, in denen ich diese gebraucht habe
Charles Roberto Canato
6
Technisch gesehen ist es keine Umgebungsvariable, sondern eine Shell-Variable. Deshalb werden Sie es nicht unter sehen env | grep OSTYPE, aber Sie werden es unter sehenset | grep OSTYPE
wisbucky
4
Für Interessenten wird die OSTYPEVariable von Bash (conftypes.h) zur Erstellungszeit unter Verwendung der exakten Kopie der OSVariablen von automake (Makefile.in) konfiguriert . Sie können die lib / config.sub- Datei von automake für alle verfügbaren Typen konsultieren .
JD Knight
9

Um auf Alberts Antwort aufzubauen, verwende ich gerne $COMSPECWindows:

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

Dies vermeidet das Parsen von Varianten von Windows-Namen für $OSund das Parsen von Varianten von unameMINGW, Cygwin usw.

Hintergrund: %COMSPEC%ist eine Windows-Umgebungsvariable, die den vollständigen Pfad zum Befehlsprozessor (auch bekannt als Windows-Shell) angibt. Der Wert dieser Variablen ist in %SystemRoot%\system32\cmd.exeder Regel der Wert , der normalerweise ausgewertet wird C:\Windows\system32\cmd.exe.

Steve Jansen
quelle
Nicht mehr korrekt, da $ COMSPEC nicht festgelegt ist, wenn es in der Windows UWS Bash-Umgebung ausgeführt wird.
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

Wenn die 6 ersten Zeichen des Befehls uname -s "CYGWIN" sind, wird ein Cygwin-System angenommen

Jan Helge
quelle
if [ `uname -s` == CYGWIN* ]; thensieht besser aus und funktioniert genauso.
David Ferenczy Rogožan
6
Ja, aber doppelte Klammern verwenden : [[ $(uname -s) == CYGWIN* ]]. Beachten Sie auch, dass erweiterte reguläre Ausdrücke in unserem Fall genauer sind : [[ $(uname -s) =~ ^CYGWIN* ]].
Andreas Spindler
Oben funktioniert besser, weil unter macOS expr substr $(uname -s) 1 6ein error ( expr: syntax error) angezeigt wird.
Doekman
2

Ok, hier ist mein Weg.

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

z.B

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

Ich benutze dies in meinen Dotfiles

wener
quelle
2

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

Alle Informationen, die Sie jemals brauchen werden. Google ist dein Freund.

Verwenden Sie uname -sdiese Option, um den Systemnamen abzufragen.

  • Mac: Darwin
  • Cygwin: CYGWIN_...
  • Linux: LINUXfür die meisten verschieden
rubenvb
quelle
2

Das Windows-Subsystem für Linux war nicht vorhanden, als diese Frage gestellt wurde. Es gab diese Ergebnisse in meinem Test:

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

Dies bedeutet, dass Sie uname -r benötigen, um es von nativem Linux zu unterscheiden.

Ein Nebel
quelle
1
Leider gibt Mingw-w64 genau das gleiche.
Ein Nebel
1

Ich denke, die uname Antwort ist unschlagbar, hauptsächlich in Bezug auf Sauberkeit.

Obwohl die Ausführung eine lächerliche Zeit in Anspruch nimmt, habe ich festgestellt, dass das Testen auf das Vorhandensein bestimmter Dateien auch gute und schnellere Ergebnisse liefert, da ich keine ausführbare Datei aufrufe:

Damit,

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

verwendet nur eine schnelle Überprüfung der Anwesenheit von Bash-Dateien. Da ich gerade unter Windows bin, kann ich Ihnen keine spezifischen Dateien für Linux und Mac OS X aus meinem Kopf sagen, aber ich bin mir ziemlich sicher, dass sie existieren. :-)

Charles Roberto Canato
quelle
-3

Verwenden Sie nur diese von der Kommandozeile funktioniert sehr gut, dank Justin:

#!/bin/bash

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

OS=`uname`
echo "$OS"

Quelle

lizardhr
quelle
Was ist neu in deinem Skript?
Mallaudin