Bagaimana cara memeriksa apakah berjalan di Cygwin, Mac atau Linux?

334

Saya memiliki skrip shell yang digunakan pada Windows / Cygwin dan Mac dan Linux. Perlu variabel yang sedikit berbeda untuk setiap versi.

Bagaimana skrip shell / bash mendeteksi apakah skrip ini berjalan di Cygwin, di Mac atau di Linux?

bastibe
sumber

Jawaban:

322

Biasanya, unamedengan berbagai opsi akan memberi tahu Anda di lingkungan mana Anda menjalankan:

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

Dan, menurut sangat membantu schot(dalam komentar), uname -smemberi Darwinuntuk OSX dan Linuxuntuk Linux, sedangkan Cygwin saya memberi CYGWIN_NT-5.1. Tetapi Anda mungkin harus bereksperimen dengan semua versi yang berbeda.

Jadi bashkode untuk melakukan pemeriksaan seperti itu ada di sepanjang baris:

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

Perhatikan bahwa saya berasumsi di sini bahwa Anda benar-benar berjalan di dalam CygWin ( bashcangkang itu) sehingga jalur seharusnya sudah diatur dengan benar. Seperti yang dicatat oleh satu komentator, Anda dapat menjalankan bashprogram, melewati skrip, dari skrip cmditu sendiri dan ini dapat mengakibatkan jalur tidak diatur sesuai kebutuhan.

Jika Anda sedang melakukan itu, itu tanggung jawab Anda untuk memastikan executable yang benar (yaitu, orang-orang Cygwin) dipanggil, mungkin dengan memodifikasi jalan terlebih dahulu atau sepenuhnya menentukan lokasi executable (misalnya, /c/cygwin/bin/uname).

paxdiablo
sumber
11
Kadang lebih sedikit lebih banyak;) BTW, Wikipedia memiliki tabel contoh keluaran tidak sama di en.wikipedia.org/wiki/Uname
schot
Git Bash uname -s output pada Windows 7 adalah MINGW32_NT-6.1. Juga, tidak ada /cygdriveawalan, hanya /cuntuk C:.
ColinM
7
Git Bash bukan Cygwin. Ini adalah MinGW, GNU minimal untuk MS Windows, itulah sebabnya perilakunya berbeda.
Boyd Stephen Smith Jr.
Saya mempromosikan jawaban lain karena jawaban ini tidak berurusan dengan bagian OP How can a shell/bash script detect ...dan yang lainnya tidak.
Jesse Chisholm
Jika saya menjalankan skrip di bawah cygwin dengan mengeksekusi "\ cygwin64 \ bin \ bash -c scriptname", ini tidak selalu berhasil. Dalam situasi ini, jalur cygwin tidak diatur dan uname -sakhirnya memanggil apa pun unameyang pertama di jalur Anda saat ini, yang pada sistem saya ternyata merupakan versi yang diinstal dengan gedayang mengembalikan teks WindowsNT. Namun bisa juga versi MinGW seperti dijelaskan di atas. Deteksi yang dapat diandalkan untuk cygwin tidak harus bergantung pada jalur yang ditetapkan dengan tepat, IMO. Karena itu, $(uname -s)harus diubah $(/bin/uname -s)untuk mendeteksi cygwin.
Jules
329

Berikut ini skrip bash yang saya gunakan untuk mendeteksi tiga tipe OS yang berbeda (GNU / Linux, Mac OS X, Windows NT)

Perhatian

  • Di skrip bash Anda, gunakan #!/usr/bin/env bashalih-alih #!/bin/shuntuk mencegah masalah yang disebabkan oleh /bin/shtertaut ke shell default yang berbeda di platform yang berbeda, atau akan ada kesalahan seperti operator yang tidak terduga , itulah yang terjadi di komputer saya (Ubuntu 64 bit 12,04).
  • Mac OS X 10.6.8 (Snow Leopard) tidak memiliki exprprogram kecuali Anda menginstalnya, jadi saya gunakan saja uname.

Rancangan

  1. Gunakan unameuntuk mendapatkan informasi sistem ( -sparameter).
  2. Gunakan exprdan substruntuk menangani string.
  3. Gunakan if elif fiuntuk melakukan pekerjaan yang cocok.
  4. Anda dapat menambahkan lebih banyak dukungan sistem jika Anda mau, cukup ikuti uname -sspesifikasinya.

Penerapan

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

Pengujian

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

Apa yang saya pelajari

  1. Periksa kutipan pembukaan dan penutupan.
  2. Periksa kurung dan kawat gigi yang hilang {}

Referensi

Albert
sumber
Untuk MinGW, mungkin lebih masuk akal untuk memeriksa: [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ].
Achal Dave
2
@Albert: ekspresi "$(expr substr $(uname -s) 1 5)"agak aneh. Ada cara yang lebih cantik untuk melakukan itu, misalnya: if [ `uname -s` == CYGWIN* ]; then. Baca: jika uname -sdimulai dengan CYGWIN maka ...
David Ferenczy Rogožan
10
@DawidFerenczy Saya percaya ini akan membutuhkan kurung ganda sepertiif [[ $(uname -s) == CYGWIN* ]]; then
rogerdpack
1
Ini tidak mendeteksi Cygwin, seperti yang ditanyakan dalam pertanyaan.
rmcclellan
2
Mengapa ini hanya memeriksa 5 karakter pertama untuk Linux? Apakah ada contoh distro Linux modern di mana uname -sakan menghasilkan sesuatu selain "Linux"?
ktbiz
127

Gunakan uname -s( --kernel-name) karena uname -o( --operating-system) tidak didukung pada beberapa Sistem Operasi seperti Mac OS dan Solaris . Anda juga dapat menggunakan hanya unametanpa argumen karena argumen defaultnya adalah -s( --kernel-name).

Cuplikan di bawah ini tidak perlu (Yaitu tidak memerlukan #!/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

Di bawah Makefileini terinspirasi dari proyek 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
...

Lihat juga jawaban lengkap ini tentang uname -sdanMakefile .

Tabel korespondensi di bagian bawah jawaban ini adalah dari artikel Wikipedia tentanguname . Silakan berkontribusi agar tetap mutakhir (edit jawaban atau kirim komentar). Anda juga dapat memperbarui artikel Wikipedia dan mengirim komentar untuk memberi tahu saya tentang kontribusi Anda ;-)

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
sumber
3
Acungan jempol untuk Solaris dan penelitian di atas.
okutane
Hai @okutane. Saya tidak mengerti apa yang Anda maksud. Harap berikan detail lebih lanjut. Apakah Anda menyarankan sesuatu? Cheers
olibre
3
Saya memilih, itu saja.
okutane
1
Inilah tepatnya yang saya cari untuk menulis portable / cross-platform ~/.profile(untuk mengatur variabel lingkungan seperti $PATH- berkomentar untuk menyediakan kata kunci pencarian untuk anak cucu).
Braham Snyder
1
Saya datang ke sini karena saya ingin mendeteksi WSL secara khusus, dan membedakannya dari Linux lain. Apa yang tampaknya berhasil bagi saya adalah memeriksa uname -srdan membandingkan dengan Linux*Microsoft)sebelumnya Linux*).
einarmagnus
65

Bash menetapkan variabel shell OSTYPE. Dari man bash:

Secara otomatis diatur ke string yang menjelaskan sistem operasi yang dijalankan bash.

Ini memiliki keuntungan kecil unamekarena tidak perlu meluncurkan proses baru, jadi akan lebih cepat untuk dijalankan.

Namun, saya tidak dapat menemukan daftar nilai yang diharapkan yang otoritatif. Bagi saya di Ubuntu 14,04 diatur ke 'linux-gnu'. Saya telah mengorek web untuk beberapa nilai lainnya. Karenanya:

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

Tanda bintang penting dalam beberapa hal - misalnya OSX menambahkan nomor versi OS setelah 'darwin'. Nilai 'win' sebenarnya adalah 'win32', saya diberitahu - mungkin ada 'win64'?

Mungkin kita dapat bekerja sama untuk mengisi tabel nilai yang diverifikasi di sini:

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

(Harap tambahkan nilai Anda jika berbeda dari entri yang ada)

Jonathan Hartley
sumber
1
Saya sudah menyukai jawaban Anda lebih dari jawaban saya, sangat cocok pada saat-saat langka yang saya butuhkan ini
Charles Roberto Canato
6
Secara teknis, ini bukan variabel lingkungan, itu variabel shell. Itu sebabnya Anda tidak akan melihatnya di bawah env | grep OSTYPE, tetapi Anda akan melihatnya di bawahset | grep OSTYPE
wisbucky
4
Bagi mereka yang tertarik, OSTYPEvariabel Bash (conftypes.h) dikonfigurasikan pada waktu build menggunakan salinan tepat dari OSvariabel automake (Makefile.in) . Seseorang dapat berkonsultasi file lib / config.sub automake untuk semua jenis yang tersedia.
jdknight
9

Untuk membangun berdasarkan jawaban Albert, saya suka menggunakan $COMSPECuntuk mendeteksi 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

Ini menghindari parsing varian nama Windows untuk $OS, dan parsing varian unameseperti MINGW, Cygwin, dll.

Latar Belakang: %COMSPEC%adalah variabel lingkungan Windows yang menetapkan jalur lengkap ke prosesor perintah (alias shell Windows). Nilai variabel ini biasanya %SystemRoot%\system32\cmd.exe, yang biasanya dievaluasi menjadi C:\Windows\system32\cmd.exe.

Steve Jansen
sumber
Tidak lagi benar karena $ COMSPEC tidak disetel saat dijalankan di bawah lingkungan 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

Jika 6 karakter pertama dari perintah uname -s adalah "CYGWIN", sebuah sistem cygwin diasumsikan

Jan Helge
sumber
if [ `uname -s` == CYGWIN* ]; thenterlihat lebih baik dan berfungsi sama.
David Ferenczy Rogožan
6
Ya, tapi menggunakan tanda kurung ganda: [[ $(uname -s) == CYGWIN* ]]. Perhatikan juga bahwa ekspresi reguler diperpanjang lebih tepat dalam kasus kami: [[ $(uname -s) =~ ^CYGWIN* ]].
Andreas Spindler
Di atas berfungsi lebih baik, karena expr substr $(uname -s) 1 6memberikan kesalahan ( expr: syntax error) pada macOS.
doekman
2

Ok, ini cara saya.

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

misalnya

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

Saya menggunakan ini di dotfiles saya

Wener
sumber
2

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

Semua info yang Anda butuhkan. Google adalah temanmu.

Gunakan uname -suntuk menanyakan nama sistem.

  • Mac: Darwin
  • Cygwin: CYGWIN_...
  • Linux: beragam, LINUXuntuk sebagian besar
rubenvb
sumber
2

Subsistem Windows untuk Linux tidak ada saat pertanyaan ini diajukan. Ini memberikan hasil ini dalam pengujian saya:

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

Ini berarti Anda perlu uname -r untuk membedakannya dari Linux asli.

A Fog
sumber
1
Sayangnya, Mingw-w64 memberikan hal yang persis sama.
A Fog
1

Saya kira jawaban yang sama tidak terkalahkan, terutama dalam hal kebersihan.

Meskipun butuh waktu yang konyol untuk mengeksekusi, saya menemukan bahwa pengujian untuk kehadiran file tertentu juga memberi saya hasil yang lebih baik dan lebih cepat, karena saya tidak menggunakan executable:

Begitu,

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

hanya menggunakan pemeriksaan kehadiran file Bash cepat. Karena saya menggunakan Windows sekarang, saya tidak dapat memberi tahu Anda file spesifik untuk Linux dan Mac OS X dari kepala saya, tetapi saya cukup yakin mereka ada. :-)

Charles Roberto Canato
sumber
-3

Gunakan ini hanya dari baris perintah yang bekerja dengan sangat baik, terima kasih kepada Justin:

#!/bin/bash

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

OS=`uname`
echo "$OS"

sumber

lizardhr
sumber
Apa yang baru dalam skrip Anda?
mallaudin