Làm cách nào để kiểm tra nếu chạy trong Cygwin, Mac hoặc Linux?


333

Tôi có một tập lệnh shell được sử dụng cả trên Windows / Cygwin và Mac và Linux. Nó cần các biến hơi khác nhau cho mỗi phiên bản.

Làm thế nào một tập lệnh shell / bash có thể phát hiện xem nó đang chạy trong Cygwin, trên máy Mac hay trong Linux?

Câu trả lời:


321

Thông thường, unamevới các tùy chọn khác nhau sẽ cho bạn biết bạn đang chạy trong môi trường nào:

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

Và, theo rất hữu ích schot(trong các bình luận), uname -scung cấp Darwincho OSX và Linuxcho Linux, trong khi Cygwin của tôi cung cấp CYGWIN_NT-5.1. Nhưng bạn có thể phải thử nghiệm với tất cả các loại phiên bản khác nhau.

Vì vậy, bashmã để thực hiện kiểm tra như vậy sẽ nằm dọc theo dòng:

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

Lưu ý rằng tôi giả sử ở đây rằng bạn thực sự đang chạy trong CygWin ( bashvỏ của nó) vì vậy các đường dẫn đã được thiết lập chính xác. Như một người bình luận lưu ý, bạn có thể chạy bashchương trình, truyền kịch bản từ cmdchính nó và điều này có thể dẫn đến các đường dẫn không được thiết lập khi cần thiết.

Nếu bạn đang làm điều đó, bạn có trách nhiệm đảm bảo các tệp thực thi chính xác (nghĩa là các CygWin) đang được gọi, có thể bằng cách sửa đổi đường dẫn trước hoặc chỉ định đầy đủ các vị trí thực thi (ví dụ /c/cygwin/bin/uname:).


11
Đôi khi ít hơn là nhiều hơn;) BTW, Wikipedia có một bảng ví dụ đầu ra uname tại en.wikipedia.org/wiki/Uname
schot

Đầu ra Git Bash uname -s trên Windows 7 là MINGW32_NT-6.1. Ngoài ra, không có /cygdrivetiền tố, chỉ /cdành cho C:.
ColinM

7
Git Bash không phải là Cygwin. Đó là MinGW, GNU tối thiểu cho MS Windows, đó là lý do tại sao hành vi này khác nhau.
Boyd Stephen Smith Jr.

Tôi đã quảng cáo câu trả lời khác vì câu trả lời này không liên quan đến phần OP How can a shell/bash script detect ...và câu trả lời khác.
Jesse Chisholm

Nếu tôi chạy tập lệnh theo cygwin bằng cách thực thi "\ cygwin64 \ bin \ bash -c scriptname", điều này không nhất thiết phải hoạt động. Trong tình huống này, đường dẫn cygwin không được thiết lập và uname -skết thúc cuộc gọi bất cứ điều gì unameđầu tiên trong đường dẫn hiện tại của bạn, mà trên hệ thống của tôi hóa ra là phiên bản được cài đặt gedatrả về văn bản WindowsNT. Nó cũng có thể là phiên bản MinGW như được mô tả ở trên. Một phát hiện đáng tin cậy cho cygwin không được dựa vào đường dẫn được đặt một cách thích hợp, IMO. Do đó, $(uname -s)nên được thay đổi $(/bin/uname -s)để phát hiện cygwin.
Jules

329

Đây là tập lệnh bash tôi đã sử dụng để phát hiện ba loại HĐH khác nhau (GNU / Linux, Mac OS X, Windows NT)

Chú ý

  • Trong tập lệnh bash của bạn, hãy sử dụng #!/usr/bin/env bashthay vì #!/bin/shđể ngăn sự cố do /bin/shliên kết với lớp vỏ mặc định khác nhau trong các nền tảng khác nhau hoặc sẽ có lỗi như toán tử bất ngờ , đó là những gì đã xảy ra trên máy tính của tôi (Ubuntu 64 bit 12.04).
  • Mac OS X 10.6.8 (Snow Leopard) không có exprchương trình trừ khi bạn cài đặt nó, vì vậy tôi chỉ sử dụng uname.

Thiết kế

  1. Sử dụng unameđể có được thông tin hệ thống ( -stham số).
  2. Sử dụng exprsubstrđể đối phó với chuỗi.
  3. Sử dụng if elif fiđể làm công việc phù hợp.
  4. Bạn có thể thêm hỗ trợ hệ thống nếu bạn muốn, chỉ cần làm theo uname -sđặc điểm kỹ thuật.

Thực hiện

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

Kiểm tra

  • Linux (Ubuntu 12.04 LTS, Kernel 3.2.0) đã thử nghiệm OK.
  • OS X (10.6.8 Snow Leopard) đã thử nghiệm OK.
  • Windows (Windows 7 64 bit) đã kiểm tra OK.

Những gì tôi học được

  1. Kiểm tra cho cả dấu ngoặc kép mở và đóng.
  2. Kiểm tra dấu ngoặc đơn và dấu ngoặc nhọn {}

Người giới thiệu


Đối với MinGW, có thể có ý nghĩa hơn để kiểm tra : [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ].
Achal Dave

2
@Albert: biểu hiện "$(expr substr $(uname -s) 1 5)"là lạ một chút. Có nhiều cách hay hơn để làm điều đó, ví dụ : if [ `uname -s` == CYGWIN* ]; then. Đọc nó: nếu uname -sbắt đầu với CYGWIN thì ...
David Ferenczy Rogožan

10
@DawidFerenczy Tôi tin rằng nó sẽ yêu cầu dấu ngoặc kép nhưif [[ $(uname -s) == CYGWIN* ]]; then
rogerdpack

1
Điều này không phát hiện Cygwin, như đã được hỏi trong câu hỏi.
rmcclellan

2
Tại sao điều này chỉ kiểm tra 5 ký tự đầu tiên cho Linux? Có ví dụ nào về các bản phân phối Linux hiện đại, nơi uname -ssẽ mang lại thứ gì đó không phải là "Linux" không?
ktbiz

126

Sử dụng uname -s( --kernel-name) vì uname -o( --operating-system) không được hỗ trợ trên một số Hệ điều hành như Mac OSSolaris . Bạn cũng có thể sử dụng unamemà không có bất kỳ đối số nào vì đối số mặc định là -s( --kernel-name).

Đoạn mã dưới đây không yêu cầu (tức là không yêu cầu #!/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

Dưới đây Makefileđược lấy cảm hứng từ dự án 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
...

Xem thêm câu trả lời đầy đủ về uname -sMakefile .

Bảng tương ứng ở dưới cùng của câu trả lời này là từ bài viết trên Wikipedia vềuname . Hãy đóng góp để giữ cho nó cập nhật (chỉnh sửa câu trả lời hoặc gửi bình luận). Bạn cũng có thể cập nhật bài viết Wikipedia và đăng bình luận để thông báo cho tôi về đóng góp của bạn ;-)

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 cho Solaris và nghiên cứu ở trên.
okutane

Xin chào @okutane. Tôi không hiểu ý của bạn là gì. Vui lòng cung cấp thêm chi tiết. Bạn có đề nghị gì không? Chúc mừng
olibre

3
Tôi đang bỏ phiếu, đó là nó.
okutane

1
Đây chính xác là những gì tôi đang tìm kiếm để viết một nền tảng di động / đa nền tảng ~/.profile(để đặt các biến môi trường như $PATH- bình luận để cung cấp từ khóa tìm kiếm cho hậu thế).
Braham Snyder

1
Tôi đến đây vì tôi muốn phát hiện WSL một cách cụ thể và phân biệt nó với các Linux khác. Những gì dường như làm việc cho tôi sau đó là kiểm tra uname -srvà so sánh với Linux*Microsoft)trước đây Linux*).
einarmagnus

65

Bash đặt biến shell OSTYPE. Từ man bash:

Tự động đặt thành một chuỗi mô tả hệ điều hành mà bash đang thực thi.

Điều này có một lợi thế rất nhỏ unameở chỗ nó không yêu cầu khởi chạy một quy trình mới, vì vậy sẽ nhanh hơn để thực hiện.

Tuy nhiên, tôi không thể tìm thấy một danh sách có thẩm quyền của các giá trị dự kiến. Đối với tôi trên Ubuntu 14.04, nó được đặt thành 'linux-gnu'. Tôi đã quét web cho một số giá trị khác. Vì thế:

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

Dấu hoa thị rất quan trọng trong một số trường hợp - ví dụ OSX nối thêm số phiên bản HĐH sau 'darwin'. Giá trị 'win' thực sự là 'win32', tôi được cho biết - có thể có 'win64'?

Có lẽ chúng ta có thể làm việc cùng nhau để đưa ra một bảng các giá trị được xác minh ở đây:

  • Linux Ubuntu (bao gồm WSL ):linux-gnu
  • Cygwin 64-bit: cygwin
  • Msys / MINGW (Git Bash cho Windows): msys

(Vui lòng nối thêm giá trị của bạn nếu nó khác với các mục hiện có)


1
Tôi đã thích câu trả lời của bạn hơn câu trả lời của tôi, hoàn toàn phù hợp với những lần hiếm hoi tôi cần điều này
Charles Roberto Canato

6
Về mặt kỹ thuật, nó không phải là biến môi trường, nó là biến vỏ. Đó là lý do tại sao bạn sẽ không thấy nó dưới env | grep OSTYPE, nhưng bạn sẽ thấy nó dướiset | grep OSTYPE
wisbucky

4
Đối với những người quan tâm, OSTYPEbiến Bash (conftypes.h) được định cấu hình tại thời điểm xây dựng bằng cách sử dụng bản sao chính xác của OSbiến automake (Makefile.in) . Người ta có thể tham khảo tệp lib / config.sub của automake cho tất cả các loại có sẵn.
jdknight

9

Để xây dựng câu trả lời của Albert, tôi muốn sử dụng $COMSPECđể phát hiện 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

Điều này tránh phân tích các biến thể của tên Windows cho $OSvà phân tích các biến thể unamenhư MINGW, Cygwin, v.v.

Bối cảnh: %COMSPEC%là biến môi trường Windows chỉ định đường dẫn đầy đủ đến bộ xử lý lệnh (hay còn gọi là vỏ Windows). Giá trị của biến này là điển hình %SystemRoot%\system32\cmd.exe, thường ước tính C:\Windows\system32\cmd.exe.


Không sửa nữa vì $ COMSPEC không được đặt khi chạy trong môi trường Windows UWS Bash.
Hiệp sĩ Julian

9
# This script fragment emits Cygwin rulez under bash/cygwin
if [[ $(uname -s) == CYGWIN* ]];then
    echo Cygwin rulez
else 
    echo Unix is king
fi

Nếu 6 ký tự đầu tiên của lệnh uname -s là "CYGWIN", thì một hệ thống cygwin được giả sử


if [ `uname -s` == CYGWIN* ]; thentrông tốt hơn và làm việc như nhau.
David Ferenczy Rogožan

6
Có, nhưng sử dụng dấu ngoặc kép : [[ $(uname -s) == CYGWIN* ]]. Cũng lưu ý rằng các biểu thức chính quy mở rộng chính xác hơn trong trường hợp của chúng tôi : [[ $(uname -s) =~ ^CYGWIN* ]].
Andreas Spindler

Ở trên hoạt động tốt hơn, vì expr substr $(uname -s) 1 6đưa ra một lỗi ( expr: syntax error) trên macOS.
doekman

2

Ok, đây là cách của tôi.

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

ví dụ

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

Tôi sử dụng điều này trong dotfiles của tôi


2

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

Tất cả các thông tin bạn sẽ cần. Google là bạn của bạn.

Sử dụng uname -sđể truy vấn tên hệ thống.

  • Mac: Darwin
  • Cygwin: CYGWIN_...
  • Linux: khác nhau, LINUXđối với hầu hết

2

Hệ thống con Windows cho Linux không tồn tại khi câu hỏi này được hỏi. Nó đã cho những kết quả này trong thử nghiệm của tôi:

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

Điều này có nghĩa là bạn cần uname -r để phân biệt với Linux nguyên gốc.


1
Thật không may, Mingw-w64 cho chính xác như vậy.
Một sương mù

1

Tôi đoán câu trả lời uname là vô địch, chủ yếu là về sự sạch sẽ.

Mặc dù phải mất một thời gian vô lý để thực thi, tôi thấy rằng việc kiểm tra sự hiện diện của các tệp cụ thể cũng mang lại cho tôi kết quả tốt và nhanh hơn, vì tôi không yêu cầu thực thi:

Vì thế,

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

chỉ cần sử dụng một kiểm tra hiện diện tập tin Bash nhanh chóng. Vì tôi đang sử dụng Windows ngay bây giờ, tôi không thể cho bạn biết bất kỳ tệp cụ thể nào dành cho Linux và Mac OS X từ đầu của tôi, nhưng tôi khá chắc chắn rằng chúng tồn tại. :-)


-3

Chỉ sử dụng điều này từ dòng lệnh hoạt động rất tốt, nhờ Justin:

#!/bin/bash

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

OS=`uname`
echo "$OS"

nguồn


Có gì mới trong kịch bản của bạn?
mallaudin
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.