จะตรวจสอบว่าทำงานใน Cygwin, Mac หรือ Linux ได้อย่างไร?


334

ฉันมีเชลล์สคริปต์ที่ใช้ทั้งบน Windows / Cygwin และ Mac และ Linux มันต้องการตัวแปรที่แตกต่างกันเล็กน้อยสำหรับแต่ละรุ่น

สคริปต์ shell / bash ตรวจพบได้อย่างไรว่าทำงานอยู่ใน Cygwin, บน Mac หรือใน Linux?

คำตอบ:


322

โดยปกติunameด้วยตัวเลือกที่หลากหลายจะบอกคุณว่าสภาพแวดล้อมของคุณกำลังทำงานอยู่:

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

และตามที่มีประโยชน์มากschot(ในความคิดเห็น) uname -sให้Darwinสำหรับ OSX และLinuxสำหรับลินุกซ์ขณะที่ Cygwin CYGWIN_NT-5.1ของฉันให้ แต่คุณอาจต้องทดลองกับรุ่นที่แตกต่างกันทุกประเภท

ดังนั้นbashรหัสในการตรวจสอบดังกล่าวจะเป็นไปตาม:

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

โปรดทราบว่าฉันสมมติว่าที่นี่คุณกำลังใช้งานจริงภายใน CygWin ( bashเชลล์ของมัน) ดังนั้นเส้นทางควรตั้งค่าไว้อย่างถูกต้องแล้ว ในฐานะผู้วิจารณ์คนหนึ่งคุณสามารถเรียกใช้bashโปรแกรมผ่านสคริปต์จากcmdตัวของมันเองและสิ่งนี้อาจส่งผลให้เส้นทางไม่ได้ถูกตั้งค่าตามต้องการ

ถ้าคุณจะทำแบบนั้นมันเป็นความรับผิดชอบของคุณเพื่อให้แน่ใจว่า executables ที่ถูกต้อง (เช่นคน Cygwin) จะถูกเรียกว่าเป็นไปได้โดยการปรับเปลี่ยนเส้นทางก่อนหรืออย่างเต็มที่ระบุสถานที่ปฏิบัติการ (เช่น/c/cygwin/bin/uname)


11
บางครั้งน้อยกว่ามาก;) BTW, Wikipedia มีตารางตัวอย่างผลลัพธ์ uname ที่en.wikipedia.org/wiki/Uname
schot

Git Bash uname -s เอาท์พุทบน Windows MINGW32_NT-6.17 นอกจากนี้ยังไม่มี/cygdriveคำนำหน้าเพียงสำหรับ/c C:
ColinM

7
Git Bash ไม่ใช่ Cygwin มันคือ MinGW, GNU ขั้นต่ำสำหรับ MS Windows ซึ่งเป็นสาเหตุที่พฤติกรรมแตกต่างกัน
Boyd Stephen Smith Jr.

ฉันเลื่อนระดับคำตอบอื่น ๆ เพราะคำตอบนี้ไม่ได้เกี่ยวข้องกับส่วน OP How can a shell/bash script detect ...และอีกคำตอบคือ
Jesse Chisholm

ถ้าฉันรันสคริปต์ภายใต้ cygwin โดยดำเนินการ "\ cygwin64 \ bin \ bash -c scriptname" สิ่งนี้ไม่จำเป็นต้องใช้งาน ในสถานการณ์เช่นนี้เส้นทาง Cygwin ไม่ได้รับการติดตั้งและuname -sจบลงด้วยการเรียกสิ่งที่unameเป็นครั้งแรกในเส้นทางปัจจุบันของคุณซึ่งในระบบของฉันเปลี่ยนจากการมีเวอร์ชันที่ติดตั้งด้วยซึ่งจะส่งกลับข้อความgeda WindowsNTแม้ว่าอาจเป็นรุ่น MinGW อย่างเท่าเทียมกันตามที่อธิบายไว้ข้างต้น การตรวจจับที่เชื่อถือได้สำหรับ cygwin จะต้องไม่พึ่งพาเส้นทางที่ตั้งไว้อย่างเหมาะสม IMO ดังนั้น$(uname -s)ควรเปลี่ยน$(/bin/uname -s)เป็นตรวจจับ cygwin
จูลส์

329

นี่คือสคริปต์ทุบตีที่ฉันใช้เพื่อตรวจหาระบบปฏิบัติการสามประเภทที่แตกต่างกัน (GNU / Linux, Mac OS X, Windows NT)

ให้ความสนใจ

  • ในสคริปต์ทุบตีของคุณใช้#!/usr/bin/env bashแทน#!/bin/shเพื่อป้องกันปัญหาที่เกิดจากการ/bin/shเชื่อมโยงไปยังเชลล์เริ่มต้นที่แตกต่างกันในแพลตฟอร์มที่แตกต่างกันหรือจะมีข้อผิดพลาดเช่นตัวดำเนินการที่ไม่คาดคิดนั่นคือสิ่งที่เกิดขึ้นบนคอมพิวเตอร์ของฉัน (Ubuntu 64 บิต 12.04)
  • Mac OS X 10.6.8 (Snow Leopard) ไม่ได้มีโปรแกรมจนกว่าคุณจะติดตั้งมันดังนั้นฉันเพียงแค่การใช้งานexpruname

ออกแบบ

  1. ใช้unameเพื่อรับข้อมูลระบบ ( -sพารามิเตอร์)
  2. ใช้exprและsubstrจัดการกับสตริง
  3. ใช้if elif fiสำหรับทำงานจับคู่
  4. คุณสามารถเพิ่มการสนับสนุนระบบได้มากขึ้นถ้าคุณต้องการเพียงแค่ทำตามuname -sข้อกำหนด

การดำเนินงาน

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

การทดสอบ

  • Linux (Ubuntu 12.04 LTS, Kernel 3.2.0) ทดสอบแล้ว
  • OS X (10.6.8 Snow Leopard) ทดสอบแล้ว
  • Windows (Windows 7 64 บิต) ทดสอบแล้ว

สิ่งที่ฉันเรียนรู้

  1. ตรวจสอบราคาเปิดและปิด
  2. ตรวจสอบวงเล็บและวงเล็บปีกกาที่หายไป {}

อ้างอิง


สำหรับ MinGW [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]ก็อาจทำให้รู้สึกมากขึ้นในการตรวจสอบ:
Achal Dave

2
@Albert: การแสดงออก"$(expr substr $(uname -s) 1 5)"เป็นบิตแปลก if [ `uname -s` == CYGWIN* ]; thenมีวิธีการที่สวยมากขึ้นที่จะทำเช่นนี้คือ: อ่าน: ถ้าuname -sเริ่มต้นด้วยCYGWINแล้ว ...
David Ferenczy Rogožan

10
@DawidFerenczy ฉันเชื่อว่ามันต้องใช้วงเล็บคู่เช่นif [[ $(uname -s) == CYGWIN* ]]; then
rogerdpack

1
สิ่งนี้ไม่ตรวจจับ Cygwin ตามที่ถามในคำถาม
rmcclellan

2
เหตุใดจึงตรวจสอบเพียง 5 ตัวอักษรแรกสำหรับ Linux? มีตัวอย่างของ distros Linux ที่ทันสมัยที่uname -sจะให้สิ่งอื่นที่ไม่ใช่ "Linux" หรือไม่?
ktbiz

127

การใช้งานuname -s( --kernel-name) เพราะuname -o( --operating-system) ไม่ได้รับการสนับสนุนบนระบบปฏิบัติการบางระบบเช่นระบบปฏิบัติการ Mac OSและSolaris คุณสามารถใช้เพียงแค่unameไม่มีอาร์กิวเมนต์ใด ๆ ก็ได้เนื่องจากอาร์กิวเมนต์เริ่มต้นคือ-s( --kernel-name)

ตัวอย่างด้านล่างไม่จำเป็นต้องใช้ (เช่นไม่ต้องการ#!/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

ด้านล่างนี้Makefileเป็นแรงบันดาลใจจากโครงการ 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
...

ดูเพิ่มเติมนี้คำตอบที่สมบูรณ์เกี่ยวกับuname -sMakefileและ

ตารางการติดต่อในด้านล่างของคำตอบนี้มาจากบทความวิกิพีเดีย unameโปรดช่วยทำให้เป็นปัจจุบัน (แก้ไขคำตอบหรือโพสต์ความคิดเห็น) คุณสามารถอัปเดตบทความ Wikipedia และโพสต์ความคิดเห็นเพื่อแจ้งให้ฉันทราบเกี่ยวกับการบริจาคของคุณ ;-)

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
Thumbs up สำหรับ Solaris และการวิจัยข้างต้น
okutane

สวัสดี @okutane ฉันไม่เข้าใจว่าคุณหมายถึงอะไร. โปรดระบุรายละเอียดเพิ่มเติม คุณแนะนำอะไรไหม Cheers
olibre

3
ฉันลงคะแนนนั่นแหล่ะ
okutane

1
นี่คือสิ่งที่ฉันกำลังมองหาเพื่อเขียนแบบพกพา / ข้ามแพลตฟอร์ม~/.profile(เพื่อตั้งค่าตัวแปรสภาพแวดล้อมเช่น$PATH- แสดงความคิดเห็นเพื่อให้คำค้นหาสำหรับลูกหลาน)
Braham Snyder

1
ฉันมาที่นี่เพราะฉันต้องการตรวจจับ WSL โดยเฉพาะและทำให้แตกต่างจาก Linux อื่น ๆ สิ่งที่ดูเหมือนจะทำงานสำหรับผมแล้วคือการตรวจสอบuname -srและเปรียบเทียบกับก่อนLinux*Microsoft) Linux*)
einarmagnus

65

Bash ตั้งค่าตัวแปรเชลล์ OSTYPE จากman bash:

ตั้งค่าเป็นสตริงที่อธิบายระบบปฏิบัติการที่ bash กำลังทำงานโดยอัตโนมัติ

นี่เป็นข้อได้เปรียบเล็ก ๆ น้อย ๆunameซึ่งไม่จำเป็นต้องมีการเปิดตัวกระบวนการใหม่ดังนั้นจึงจะสามารถดำเนินการได้เร็วขึ้น

อย่างไรก็ตามฉันไม่พบรายการที่มีสิทธิ์ของค่าที่คาดหวัง สำหรับฉันบน Ubuntu 14.04 มันถูกตั้งค่าเป็น 'linux-gnu' ฉันคัดลอกเว็บเพื่อหาค่าอื่น ดังนั้น:

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

เครื่องหมายดอกจันมีความสำคัญในบางกรณี - ตัวอย่างเช่น OSX ต่อท้ายหมายเลขเวอร์ชั่นระบบปฏิบัติการหลังจาก 'ดาร์วิน' ค่า 'ชนะ' จริง ๆ แล้วคือ 'win32' ฉันบอกแล้ว - อาจมี 'win64' หรือ

บางทีเราสามารถทำงานร่วมกันเพื่อเติมตารางค่าการตรวจสอบที่นี่:

  • Linux Ubuntu (รวมถึงWSL ):linux-gnu
  • Cygwin 64-bit: cygwin
  • Msys / MINGW (Git Bash สำหรับ Windows): msys

(โปรดเพิ่มมูลค่าของคุณต่อท้ายหากแตกต่างจากรายการที่มีอยู่)


1
ฉันชอบคำตอบของคุณมากกว่าของฉันแล้วพอดีในเวลาที่หายากที่ฉันต้องการ
Charles Roberto Canato

6
ในทางเทคนิคแล้วมันไม่ใช่ตัวแปรสภาพแวดล้อมมันเป็นตัวแปรเชลล์ นั่นเป็นเหตุผลที่คุณจะไม่เห็นมันใต้env | grep OSTYPEแต่คุณจะเห็นมันภายใต้set | grep OSTYPE
wisbucky

4
สำหรับผู้ที่สนใจทุบตีของOSTYPEตัวแปร(conftypes.h)มีการกำหนดค่าเวลาที่สร้างโดยใช้สำเนาถูกต้องของ automake ของOSตัวแปร(Makefile.in) หนึ่งอาจศึกษาไฟล์lib / config.subของ automake สำหรับประเภทที่มีทั้งหมด
jdknight

9

เพื่อสร้างตามคำตอบของ Albert ฉันชอบใช้$COMSPECตรวจจับ 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

วิธีนี้จะหลีกเลี่ยงการวิเคราะห์คำที่แตกต่างของชื่อ Windows สำหรับ$OSและการแยกคำที่มีความหมายunameเช่น MINGW, Cygwin ฯลฯ

พื้นหลัง: %COMSPEC%เป็นตัวแปรสภาพแวดล้อมของ Windows ที่ระบุพา ธ แบบเต็มไปยังตัวประมวลผลคำสั่ง (aka เชลล์ Windows) ค่าของตัวแปรนี้เป็นปกติซึ่งมักจะประเมิน%SystemRoot%\system32\cmd.exeC:\Windows\system32\cmd.exe


ไม่ถูกต้องอีกต่อไปเนื่องจากไม่ได้ตั้งค่า $ COMSPEC เมื่อทำงานภายใต้สภาพแวดล้อม 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

หาก 6 ตัวอักษรแรกของคำสั่ง uname -s คือ "CYGWIN" ระบบ cygwin จะถูกใช้


if [ `uname -s` == CYGWIN* ]; thenดูดีขึ้นและทำงานเหมือนเดิม
David Ferenczy Rogožan

6
ใช่ แต่ใช้วงเล็บสองตัว: [[ $(uname -s) == CYGWIN* ]]. [[ $(uname -s) =~ ^CYGWIN* ]]ยังทราบว่าการแสดงออกปกติขยายมีความแม่นยำมากขึ้นในกรณีของเรา:
Andreas Spindler

ข้างต้นทำงานได้ดีขึ้นเพราะexpr substr $(uname -s) 1 6ให้ข้อผิดพลาด ( expr: syntax error) กับ macOS
doekman

2

ตกลงนี่เป็นวิธีของฉัน

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

เช่น

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

ฉันใช้สิ่งนี้ในdotfilesของฉัน


2

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

ข้อมูลทั้งหมดที่คุณต้องการ Google คือเพื่อนของคุณ

ใช้uname -sเพื่อสืบค้นชื่อระบบ

  • Mac: Darwin
  • Cygwin: CYGWIN_...
  • Linux: หลากหลายLINUXที่สุด

2

Windows Subsystem สำหรับ Linux ไม่มีอยู่เมื่อมีการถามคำถามนี้ มันให้ผลลัพธ์เหล่านี้ในการทดสอบของฉัน:

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

ซึ่งหมายความว่าคุณต้องการ uname -r เพื่อแยกความแตกต่างจาก native Linux


1
น่าเสียดาย Mingw-w64 ก็ให้เหมือนกันทุกประการ
หมอก

1

ฉันเดาว่าคำตอบที่ไม่มีชื่อเป็นสิ่งที่เอาชนะได้ส่วนใหญ่ในแง่ของความสะอาด

แม้ว่าจะต้องใช้เวลาในการดำเนินการที่น่าขัน แต่ฉันพบว่าการทดสอบไฟล์ที่มีอยู่นั้นยังให้ผลลัพธ์ที่ดีและรวดเร็วกว่าด้วยเนื่องจากฉันไม่ได้เรียกใช้ไฟล์ปฏิบัติการ:

ดังนั้น,

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

เพียงใช้การตรวจสอบสถานะไฟล์ Bash อย่างรวดเร็ว ตอนนี้ฉันใช้ Windows ฉันไม่สามารถบอกไฟล์เฉพาะสำหรับ Linux และ Mac OS X จากหัวของฉันได้ แต่ฉันค่อนข้างมั่นใจว่ามันมีอยู่จริง :-)


-3

ใช้สิ่งนี้จากบรรทัดคำสั่งทำงานได้ดีมากขอบคุณ Justin:

#!/bin/bash

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

OS=`uname`
echo "$OS"

แหล่ง


มีอะไรใหม่ในสคริปต์ของคุณ?
mallaudin
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.