Come verificare se in esecuzione su Cygwin, Mac o Linux?


334

Ho uno script di shell che viene utilizzato sia su Windows / Cygwin che su Mac e Linux. Ha bisogno di variabili leggermente diverse per ogni versione.

Come può uno script shell / bash rilevare se è in esecuzione su Cygwin, su un Mac o su Linux?

Risposte:


322

Di solito, unamecon le sue varie opzioni, ti dirà in quale ambiente stai eseguendo:

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

E, secondo l'utilissimo schot(nei commenti), uname -sDarwinper OSX e Linuxper Linux, mentre il mio Cygwin dà CYGWIN_NT-5.1. Ma potresti dover sperimentare tutti i tipi di versioni diverse.

Quindi il bashcodice per fare un tale controllo sarebbe sulla falsariga di:

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

Si noti che sto dando per scontato che si sta effettivamente in esecuzione all'interno CygWin (la bashshell di esso) in modo da percorsi dovrebbero già essere impostati correttamente. Come osserva un commentatore, è possibile eseguire il bashprogramma, passando lo script, da cmdsolo e ciò può comportare che i percorsi non vengano impostati come necessario.

Se lo stai facendo, è tua responsabilità assicurarti che vengano richiamati gli eseguibili corretti (cioè quelli CygWin), possibilmente modificando in anticipo il percorso o specificando completamente le posizioni degli eseguibili (ad es /c/cygwin/bin/uname.).


11
A volte meno è di più;) A proposito, Wikipedia ha una tabella di esempio uname output su en.wikipedia.org/wiki/Uname
schot

L'output di Git Bash uname -s su Windows 7 è MINGW32_NT-6.1. Inoltre, non esiste un /cygdriveprefisso, solo /cper C:.
ColinM,

7
Git Bash non è Cygwin. È MinGW, GNU minimo per MS Windows, motivo per cui il comportamento è diverso.
Boyd Stephen Smith Jr.,

Ho promosso l'altra risposta perché questa risposta non ha a che fare con la parte OP How can a shell/bash script detect ...e l'altra no .
Jesse Chisholm,

Se eseguo uno script con Cygwin eseguendo "\ cygwin64 \ bin \ bash -c nome script", questo non funziona necessariamente. In questa situazione, il percorso di Cygwin non viene impostato e uname -sfinisce per chiamare qualunque cosa unamesia la prima nel tuo percorso corrente, che sul mio sistema risulta essere la versione installata con la gedaquale restituisce il testo WindowsNT. Potrebbe ugualmente essere la versione di MinGW come descritto sopra, però. Un rilevamento affidabile per Cygwin non deve basarsi sul percorso impostato in modo appropriato, IMO. Pertanto, $(uname -s)dovrebbe essere modificato $(/bin/uname -s)per rilevare Cygwin.
Jules il

329

Ecco lo script bash che ho usato per rilevare tre diversi tipi di sistema operativo (GNU / Linux, Mac OS X, Windows NT)

Fai attenzione

  • Nel tuo script bash, usa #!/usr/bin/env bashinvece di #!/bin/shper evitare il problema causato dal /bin/shcollegamento a diverse shell predefinite in piattaforme diverse, o ci saranno errori come operatori imprevisti , ecco cosa è successo sul mio computer (Ubuntu 64 bit 12.04).
  • Mac OS X 10.6.8 (Snow Leopard) non ha un exprprogramma se non lo installi, quindi lo uso e basta uname.

Design

  1. Utilizzare unameper ottenere le informazioni di sistema (-s parametro).
  2. Usa expresubstr gestire la stringa.
  3. Uso if elif fi per eseguire il lavoro corrispondente.
  4. Se lo desideri, puoi aggiungere ulteriore supporto al sistema, basta seguire le uname -sspecifiche.

Implementazione

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

analisi

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

Quello che ho imparato

  1. Verificare le virgolette di apertura e chiusura.
  2. Verifica la presenza di parentesi e parentesi graffe mancanti {}

Riferimenti


Per MinGW, potrebbe avere più senso per controllare: [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ].
Achal Dave,

2
@Albert: l'espressione "$(expr substr $(uname -s) 1 5)"è un po 'strana. Ci sono più belle modi per farlo, per esempio: if [ `uname -s` == CYGWIN* ]; then. Leggi: se uname -sinizia con CYGWIN, allora ...
David Ferenczy Rogožan

10
@DawidFerenczy Credo che richiederebbe doppie parentesi comeif [[ $(uname -s) == CYGWIN* ]]; then
rogerdpack

1
Questo non rileva Cygwin, come è stato chiesto nella domanda.
rmcclellan,

2
Perché questo controlla solo i primi 5 caratteri per Linux? Ci sono esempi di distro Linux moderne dove uname -sprodurrà qualcosa di diverso da "Linux"?
ktbiz,

127

Usa uname -s( --kernel-name) perché uname -o( --operating-system) non è supportato su alcuni sistemi operativi come Mac OS e Solaris . Puoi anche usare solo unamesenza alcun argomento poiché l'argomento predefinito è -s( --kernel-name).

Lo snippet di seguito non richiede (cioè non richiede #!/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

Il seguito Makefileè ispirato al progetto 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
...

Vedi anche questa risposta completa su uname -seMakefile .

La tabella delle corrispondenze in fondo a questa risposta è tratta dall'articolo di Wikipedia suuname . Contribuisci a mantenerlo aggiornato (modifica la risposta o pubblica un commento). Puoi anche aggiornare l'articolo di Wikipedia e pubblicare un commento per avvisarmi del tuo contributo ;-)

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
Complimenti per Solaris e ricerche sopra.
Okutane,

Ciao @okutane. Non capisco cosa intendi. Si prega di fornire maggiori dettagli. Suggerisci qualcosa? Saluti
olibre,

3
Sto votando, tutto qui.
Okutane,

1
Questo è esattamente quello che stavo cercando per scrivere una piattaforma portatile / multipiattaforma ~/.profile(per impostare variabili d'ambiente come $PATH- commentare per fornire parole chiave di ricerca per i posteri).
Braham Snyder,

1
Sono venuto qui perché volevo rilevare WSL in modo specifico e differenziarlo da altri Linux. Ciò che sembra funzionare per me allora è controllare uname -sre confrontare Linux*Microsoft)prima Linux*).
einarmagnus,

65

Bash imposta la variabile shell OSTYPE. Da man bash:

Impostato automaticamente su una stringa che descrive il sistema operativo su cui è in esecuzione bash.

Questo ha un piccolo vantaggio unamein quanto non richiede l'avvio di un nuovo processo, quindi sarà più veloce da eseguire.

Tuttavia, non riesco a trovare un elenco autorevole di valori previsti. Per me su Ubuntu 14.04 è impostato su "linux-gnu". Ho raschiato il web per altri valori. Quindi:

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

Gli asterischi sono importanti in alcuni casi, ad esempio OSX aggiunge un numero di versione del sistema operativo dopo "darwin". Il valore 'win' è in realtà 'win32', mi viene detto - forse c'è un 'win64'?

Forse potremmo lavorare insieme per popolare una tabella di valori verificati qui:

  • Linux Ubuntu (incl. WSL ):linux-gnu
  • Cygwin 64-bit: cygwin
  • Msys / MINGW (Git Bash per Windows): msys

(Aggiungi il tuo valore se differisce dalle voci esistenti)


1
Mi piace già la tua risposta più della mia, si adatta perfettamente alle rare volte in cui ne ho avuto bisogno
Charles Roberto Canato,

6
Tecnicamente, non è una variabile d'ambiente, è una variabile di shell. Ecco perché non lo vedrai sotto env | grep OSTYPE, ma lo vedrai sottoset | grep OSTYPE
wisbucky

4
Per gli interessati, la OSTYPEvariabile di Bash (conftypes.h) è configurata al momento della compilazione usando la copia esatta della OSvariabile di automake (Makefile.in) . Si può consultare il file lib / config.sub di automake per tutti i tipi disponibili.
jdknight,

9

Per basarmi sulla risposta di Albert, mi piace usare $COMSPECper rilevare 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

Questo evita l'analisi delle varianti dei nomi di Windows $OSe l'analisi delle varianti unamecome MINGW, Cygwin, ecc.

Sfondo: %COMSPEC%è una variabile ambientale di Windows che specifica il percorso completo del processore dei comandi (noto anche come shell di Windows). Il valore di questa variabile è in genere %SystemRoot%\system32\cmd.exe, che in genere viene valutato C:\Windows\system32\cmd.exe.


Non correggere più poiché $ COMSPEC non è impostato durante l'esecuzione nell'ambiente 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

Se i primi 6 caratteri del comando uname -s sono "CYGWIN", si assume un sistema cygwin


if [ `uname -s` == CYGWIN* ]; thensembra migliore e funziona allo stesso modo.
David Ferenczy Rogožan,

6
Sì, ma utilizzare le doppie parentesi quadre: [[ $(uname -s) == CYGWIN* ]]. Si noti inoltre che estesi espressioni regolari sono più precisi nel nostro caso: [[ $(uname -s) =~ ^CYGWIN* ]].
Andreas Spindler,

Sopra funziona meglio, perché expr substr $(uname -s) 1 6dà un errore ( expr: syntax error) su macOS.
doekman,

2

Ok, ecco la mia strada.

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

per esempio

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

Lo uso nei miei dotfile


2

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

Tutte le informazioni di cui avrai mai bisogno. Google è tuo amico.

Utilizzare uname -sper interrogare il nome del sistema.

  • Mac: Darwin
  • Cygwin: CYGWIN_...
  • Linux: vari, LINUXper la maggior parte

2

Il sottosistema Windows per Linux non esisteva quando veniva posta questa domanda. Ha dato questi risultati nel mio test:

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

Ciò significa che è necessario uname -r per distinguerlo da Linux nativo.


1
Sfortunatamente, Mingw-w64 dà esattamente lo stesso.
Una nebbia

1

Immagino che la risposta sbagliata sia imbattibile, soprattutto in termini di pulizia.

Anche se ci vuole un tempo ridicolo per eseguire, ho scoperto che il test per la presenza di file specifici mi dà anche risultati buoni e più rapidi, dal momento che non sto invocando un eseguibile:

Così,

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

utilizza solo un rapido controllo di presenza del file Bash. Dato che sono su Windows in questo momento, non posso dirti alcun file specifico per Linux e Mac OS X dalla mia testa, ma sono abbastanza sicuro che esistano. :-)


-3

Utilizzare solo questo dalla riga di comando funziona molto bene, grazie a Justin:

#!/bin/bash

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

OS=`uname`
echo "$OS"

fonte


Cosa c'è di nuovo nella tua sceneggiatura?
Mallaudin,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.