Jak sprawdzić, czy działa w Cygwin, Mac lub Linux?

334

Mam skrypt powłoki używany zarówno w systemach Windows / Cygwin, Mac, jak i Linux. Potrzebuje nieco innych zmiennych dla każdej wersji.

W jaki sposób skrypt powłoki / bash może wykryć, czy działa w Cygwin, na Macu czy w Linuksie?

bastibe
źródło

Odpowiedzi:

322

Zazwyczaj unamedzięki różnym opcjom powiesz w jakim środowisku pracujesz:

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

I, zgodnie z bardzo pomocnymi schot(w komentarzach), uname -sdaje Darwindla OSX i Linuxdla Linuksa, podczas gdy mój Cygwin daje CYGWIN_NT-5.1. Ale być może będziesz musiał poeksperymentować z różnego rodzaju wersjami.

Tak więc bashkod do wykonania takiej kontroli byłby następujący:

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

Zauważ, że zakładam tutaj, że faktycznie działasz w CygWin (jego bashpowłoce), więc ścieżki powinny być już poprawnie ustawione. Jak zauważa jeden z komentatorów, możesz uruchomić bashprogram, przekazując skrypt od cmdsiebie, co może spowodować, że ścieżki nie zostaną skonfigurowane w razie potrzeby.

Jeśli to robisz, Twoim obowiązkiem jest upewnić się, że wywoływane są poprawne pliki wykonywalne (tj. CygWin), być może poprzez uprzednią modyfikację ścieżki lub pełne określenie plików wykonywalnych (np /c/cygwin/bin/uname.).

paxdiablo
źródło
11
Czasami mniej znaczy więcej;) BTW, Wikipedia ma tabelę przykładowych wyników uname na en.wikipedia.org/wiki/Unazwa
schot
Wyjście Game Bash uname -s w systemie Windows 7 to MINGW32_NT-6.1. Ponadto nie ma /cygdriveprzedrostka, tylko /cdla C:.
ColinM
7
Git Bash to nie Cygwin. Jest to MinGW, minimalny GNU dla MS Windows, dlatego zachowanie jest inne.
Boyd Stephen Smith Jr.
Promowałem drugą odpowiedź, ponieważ ta odpowiedź nie dotyczy części OP, How can a shell/bash script detect ...a druga tak.
Jesse Chisholm,
Jeśli uruchomię skrypt w programie cygwin, wykonując polecenie „\ cygwin64 \ bin \ bash -c nazwa skryptu”, nie musi to działać. W tej sytuacji ścieżka cygwina nie jest konfigurowana i uname -skończy się wywoływaniem tego, co unamepierwsze na twojej bieżącej ścieżce, które w moim systemie okazuje się być zainstalowaną wersją, gedaktóra zwraca tekst WindowsNT. Może to być jednak wersja MinGW, jak opisano powyżej. Wiarygodne wykrywanie cygwina nie może polegać na odpowiednio ustawionej ścieżce, IMO. Dlatego $(uname -s)powinien zostać zmieniony $(/bin/uname -s)na wykrywanie cygwina.
Jules
329

Oto skrypt bash, którego użyłem do wykrycia trzech różnych typów systemów operacyjnych (GNU / Linux, Mac OS X, Windows NT)

Zwróć uwagę

  • W skrypcie bash używaj #!/usr/bin/env bashzamiast, #!/bin/shaby zapobiec problemowi związanemu z /bin/shpołączeniem z inną domyślną powłoką na różnych platformach, w przeciwnym razie wystąpi błąd, taki jak nieoczekiwany operator , tak się stało na moim komputerze (Ubuntu 64 bity 12.04).
  • Mac OS X 10.6.8 (Snow Leopard) nie ma exprprogramu, chyba że go zainstalujesz, więc po prostu go używam uname.

Projekt

  1. Służy unamedo uzyskania informacji o systemie ( -sparametr).
  2. Użyj expri, substraby poradzić sobie z ciągiem.
  3. Użyj, if elif fiaby wykonać pasującą pracę.
  4. Możesz dodać więcej wsparcia systemowego, jeśli chcesz, wystarczy postępować zgodnie ze uname -sspecyfikacją.

Realizacja

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

Testowanie

  • Linux (Ubuntu 12.04 LTS, Kernel 3.2.0) przetestował OK.
  • System OS X (10.6.8 Snow Leopard) przetestował OK.
  • Windows (Windows 7 64 bit) przetestował OK.

Czego się nauczyłem

  1. Sprawdź zarówno otwierające, jak i zamykające oferty.
  2. Sprawdź brakujące nawiasy i nawiasy klamrowe {}

Bibliografia

Albert
źródło
Dla MinGW, może to więcej sensu, aby sprawdzić: [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ].
Achal Dave
2
@Albert: wyrażenie "$(expr substr $(uname -s) 1 5)"jest trochę dziwne. Są bardziej ładne sposobów aby to zrobić, na przykład: if [ `uname -s` == CYGWIN* ]; then. Przeczytaj: jeśli uname -szaczyna się od CYGWIN, to ...
David Ferenczy Rogožan
10
@DawidFerenczy Wierzę, że wymagałoby to podwójnych nawiasów jakif [[ $(uname -s) == CYGWIN* ]]; then
rogerdpack
1
Nie wykrywa to Cygwina, o co pytano w pytaniu.
rmcclellan
2
Dlaczego sprawdza to tylko pierwsze 5 znaków w systemie Linux? Czy istnieją przykłady współczesnych dystrybucji Linuksa, w których uname -smożna uzyskać coś innego niż „Linux”?
ktbiz
127

Użyj uname -s( --kernel-name), ponieważ uname -o( --operating-system) nie jest obsługiwane w niektórych systemach operacyjnych, takich jak Mac OS i Solaris . Możesz także użyć unamebez żadnego argumentu, ponieważ domyślnym argumentem jest -s( --kernel-name).

Poniższy fragment kodu nie wymaga (tj. nie wymaga #!/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

Poniżej Makefileinspirowane jest projektem 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
...

Zobacz także pełną odpowiedź na temat uname -siMakefile .

Tabela korespondencji na dole tej odpowiedzi pochodzi z artykułu w Wikipedii na tematuname . Proszę przyczynić się do jego aktualności (edytuj odpowiedź lub opublikuj komentarz). Możesz również zaktualizować artykuł w Wikipedii i opublikować komentarz, aby powiadomić mnie o swoim wkładzie ;-)

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
źródło
3
Kciuki za Solaris i badania powyżej.
okutane
Cześć @okutane. Nie rozumiem o co ci chodzi. Podaj więcej szczegółów. Sugerujesz coś? Pozdrawiam
olibre
3
Głosuję, to wszystko.
okutane
1
Właśnie tego szukałem, aby napisać przenośny / międzyplatformowy ~/.profile (aby ustawić zmienne środowiskowe, takie jak $PATH- komentowanie w celu zapewnienia słów kluczowych dla potomności).
Braham Snyder
1
Przybyłem tutaj, ponieważ chciałem konkretnie wykryć WSL i odróżnić go od innych Linuksów. Wydaje mi się, że wtedy sprawdzam uname -sri porównuję Linux*Microsoft)wcześniej Linux*).
einarmagnus
65

Bash ustawia zmienną powłoki OSTYPE. Od man bash:

Automatycznie ustawiany na ciąg znaków opisujący system operacyjny, w którym wykonuje się bash.

Ma to niewielką przewagę nad unametym, że nie wymaga uruchamiania nowego procesu, więc będzie można go szybciej wykonać.

Nie mogę jednak znaleźć wiarygodnej listy oczekiwanych wartości. Dla mnie na Ubuntu 14.04 jest ustawiony na „linux-gnu”. Zeskrobałem sieć w poszukiwaniu innych wartości. W związku z tym:

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

Gwiazdki są ważne w niektórych przypadkach - na przykład OSX dołącza numer wersji systemu operacyjnego po „darwin”. Powiedziano mi, że wartość „win” to tak naprawdę „win32” - może istnieje „win64”?

Być może moglibyśmy pracować razem, aby wypełnić tabelę zweryfikowanych wartości tutaj:

  • Linux Ubuntu (w tym WSL ):linux-gnu
  • Cygwin 64-bit: cygwin
  • Msys / MINGW (Git Bash dla Windows): msys

(Proszę dołączyć swoją wartość, jeśli różni się ona od istniejących pozycji)

Jonathan Hartley
źródło
1
Już lubię twoją odpowiedź bardziej niż moją, pasuje idealnie w tych rzadkich chwilach, kiedy tego potrzebowałem
Charles Roberto Canato,
6
Technicznie rzecz biorąc, nie jest to zmienna środowiskowa, to zmienna powłoki. Dlatego nie zobaczysz tego pod env | grep OSTYPEset | grep OSTYPE
spodem
4
Dla zainteresowanych OSTYPEzmienna Basha (conftypes.h) jest konfigurowana w czasie kompilacji przy użyciu dokładnej kopii OSzmiennej automake (Makefile.in) . Można sprawdzić plik lib / config.sub automake dla wszystkich dostępnych typów.
jdknight
9

Opierając się na odpowiedzi Alberta, lubię używać $COMSPECdo wykrywania systemu 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

Pozwala to uniknąć analizowania wariantów nazw systemu Windows $OSi analizowania wariantówuname takich jak MINGW, Cygwin itp.

Tło: %COMSPEC%to zmienna środowiskowa systemu Windows określająca pełną ścieżkę do procesora poleceń (zwanego również powłoką systemu Windows). Wartość tej zmiennej wynosi zazwyczaj %SystemRoot%\system32\cmd.exe, co zwykle stanowi wartość C:\Windows\system32\cmd.exe.

Steve Jansen
źródło
Nie poprawiaj więcej, ponieważ $ COMSPEC nie jest ustawiony, gdy działa w środowisku 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

Jeśli 6 pierwszych znaków komendy uname -s to „CYGWIN”, zakłada się system cygwin

Jan Helge
źródło
if [ `uname -s` == CYGWIN* ]; thenwygląda lepiej i działa tak samo.
David Ferenczy Rogožan
6
Tak, ale używać podwójnych nawiasów: [[ $(uname -s) == CYGWIN* ]]. Należy również zauważyć, że rozszerzone wyrażenia regularne są bardziej precyzyjne w naszym przypadku: [[ $(uname -s) =~ ^CYGWIN* ]].
Andreas Spindler
Powyżej działa lepiej, ponieważ expr substr $(uname -s) 1 6daje błąd ( expr: syntax error) w systemie macOS.
doekman
2

Ok, oto moja droga.

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

na przykład

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

Używam tego w moich plikach dot

wener
źródło
2

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

Wszystkie informacje, których kiedykolwiek będziesz potrzebować. Google to twój przyjaciel.

Służy uname -sdo zapytania o nazwę systemu.

  • Prochowiec: Darwin
  • Cygwin: CYGWIN_...
  • Linux: różne, LINUXdla większości
rubenvb
źródło
2

Podsystem Windows dla systemu Linux nie istniał, gdy zadano to pytanie. Dało to wyniki w moim teście:

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

Oznacza to, że potrzebujesz uname -r, aby odróżnić go od natywnego Linuksa.

Mgła
źródło
1
Niestety Mingw-w64 daje dokładnie to samo.
A Fog
1

Myślę, że nieznajoma odpowiedź jest bezkonkurencyjna, głównie pod względem czystości.

Chociaż wykonanie zajmuje absurdalnie dużo czasu, okazało się, że testowanie obecności określonych plików daje mi również dobre i szybsze wyniki, ponieważ nie wywołuję pliku wykonywalnego:

Więc,

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

po prostu używa szybkiego sprawdzania obecności pliku Bash. Ponieważ jestem teraz w systemie Windows, nie mogę powiedzieć ci żadnych konkretnych plików dla systemu Linux i Mac OS X z mojej głowy, ale jestem prawie pewien, że istnieją. :-)

Charles Roberto Canato
źródło
-3

Używaj tylko tego z wiersza poleceń, działa bardzo dobrze, dzięki Justin:

#!/bin/bash

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

OS=`uname`
echo "$OS"

źródło

jaszczur
źródło
Co nowego w twoim skrypcie?
mallaudin