Як перевірити, чи працює у 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для 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себе, і це може призвести до того, що шляхи не будуть встановлені за необхідності.

Якщо ви це робите, ви зобов'язані забезпечити виклик правильних виконуваних файлів (тобто CygWin), можливо, попередньо змінивши шлях або повністю вказавши місця для виконання файлів (наприклад, /c/cygwin/bin/uname).


11
Іноді менше - більше;) До речі, у Вікіпедії є таблиця прикладів, що не мають статусу на сайті en.wikipedia.org/wiki/Uname
знімок

Вихідні дані Git Bash у Windows 7 є MINGW32_NT-6.1. Також /cygdriveпрефікса немає , просто /cдля C:.
ColinM

7
Гіт Баш - це не Сигвін. Це MinGW, мінімальний GNU для MS Windows, через що поведінка відрізняється.
Бойд Стівен Сміт-молодший

Я запропонував іншу відповідь, оскільки ця відповідь не стосується частини ОП, How can a shell/bash script detect ...а інша.
Джессі Чизгольм

Якщо я запускаю скрипт під cygwin, виконуючи "\ cygwin64 \ bin \ bash -c ім'я скрипта", це не обов'язково працює. У цій ситуації шлях cygwin не встановлюється і uname -sзакінчується викликом того, що unameє першим у вашому поточному шляху, який у моїй системі виявляється встановленою версією, з gedaякою повертає текст WindowsNT. Хоча це може бути однаково версією MinGW, як описано вище. Надійне виявлення cygwin не повинно покладатися на відповідний шлях, IMO. Тому $(uname -s)слід змінити, $(/bin/uname -s)щоб виявити цигвін.
Жуль

329

Ось сценарій bash, який я використовував для виявлення трьох різних типів ОС (GNU / Linux, Mac OS X, Windows NT)

Звернути увагу

  • У вашому скрипті bash використовуйте #!/usr/bin/env bashзамість того, #!/bin/shщоб запобігти проблемі, викликаній /bin/shзв’язком з різними оболонками за замовчуванням на різних платформах, інакше буде помилка, як несподіваний оператор , ось що трапилося на моєму комп’ютері (Ubuntu 64 біт 12.04).
  • У Mac OS X 10.6.8 (Snow Leopard) немає exprпрограми, якщо ви її не встановите, тому я просто користуюся uname.

Дизайн

  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, ядро ​​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" ].
Ахал Дейв

2
@Albert: вираз "$(expr substr $(uname -s) 1 5)"трохи дивний. Є більш красиві способи зробити це, наприклад: if [ `uname -s` == CYGWIN* ]; then. Прочитайте: якщо uname -sпочинається з CYGWIN, то ...
Девід Ференчі Рогожан

10
@DawidFerenczy Я вважаю, що для цього знадобляться подвійні дужки, наприкладif [[ $(uname -s) == CYGWIN* ]]; then
rogerdpack

1
Це не виявляє Cygwin, як було задано в запитанні.
rmcclellan

2
Чому це перевіряє лише перші 5 символів для Linux? Чи є приклади сучасних дистрибутивів 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 -sтаMakefile .

Таблиця листування внизу цієї відповіді - зі статті Вікіпедії оuname . Будь ласка, зробіть свій внесок у оновлення оновлення (відредагуйте відповідь або опублікуйте коментар). Ви також можете оновити статтю у Вікіпедії та опублікувати коментар, щоб повідомити мене про ваш внесок ;-)

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
Великі пальці для Solaris і дослідження вище.
окутане

Привіт @okutane. Я не розумію що ти маєш на увазі. Надайте більше деталей. Ви щось пропонуєте? Ура
олібре

3
Я голосую, ось і все.
окутане

1
Це саме те, що я шукав для того, щоб написати портативну / крос-платформу ~/.profile(встановити змінні середовища, як-от $PATH- коментуючи, щоб надати пошукові ключові слова для нащадків).
Брахам Снайдер

1
Я прийшов сюди, тому що хотів конкретно виявити WSL і відрізнити його від інших Linuxes. Що, здається, для мене працює, це перевірити 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 додає номер версії ОС після 'darwin'. Значення "win" насправді "win32", мені кажуть - можливо, є "win64"?

Можливо, ми могли б працювати разом, щоб заповнити таблицю перевірених значень тут:

  • Linux Ubuntu (включаючи WSL ):linux-gnu
  • 64-бітний Cygwin: cygwin
  • Msys / MINGW (Git Bash для Windows): msys

(Будь ласка, додайте свою вартість, якщо вона відрізняється від існуючих записів)


1
Мені вже подобається ваша відповідь більше, ніж моя, ідеально підходить для тих рідких випадків, коли мені це потрібно
Чарльз Роберто Канато,

6
Технічно це не змінна середовище, це змінна оболонка. Ось чому ви не побачите його під env | grep OSTYPE, але ви побачите його підset | grep OSTYPE
wisbucky

4
Для тих, хто цікавиться, OSTYPEзмінна Bash (conftypes.h) налаштовується під час збирання за допомогою точної копії OSзмінної automake (Makefile.in) . Можна звернутися до файлу lib / config.sub автоматики для всіх доступних типів.
jdknight

9

На основі відповіді Альберта я люблю використовувати $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 із зазначенням повного шляху до командного процесора (він же оболонки Windows). Значення цієї змінної, як %SystemRoot%\system32\cmd.exeправило, оцінює до C:\Windows\system32\cmd.exe.


Більше не виправляйте, оскільки $ COMSPEC не встановлено під час роботи в середовищі Windows UWS Bash.
Джуліан Найт

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 перших символів команди unme -s - "CYGWIN", передбачається система cygwin


if [ `uname -s` == CYGWIN* ]; thenвиглядає краще і працює так само.
Девід Ференці Рогожан

6
Так, але використовувати подвійні дужки: [[ $(uname -s) == CYGWIN* ]]. Слід також зазначити , що розширені регулярні вирази є більш точними в нашому випадку: [[ $(uname -s) =~ ^CYGWIN* ]].
Андреас Шпіндлер

Вище працює краще, тому що 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
}

Я використовую це у своїх дотфайлах


2

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

Вся інформація, яка вам коли-небудь знадобиться. Google - ваш друг.

Використовуйте uname -sдля запиту назви системи.

  • Мак: Darwin
  • Cygwin: CYGWIN_...
  • Linux: різні LINUXдля більшості

2

Підсистема Windows для Linux не існувала, коли було задано це питання. Це дало такі результати в моєму тесті:

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

Це означає, що вам потрібно uname -r, щоб відрізнити його від рідного Linux.


1
На жаль, Mingw-w64 дає саме те саме.
Туман

1

Я думаю, що невірна відповідь є неперевершеною, головним чином з точки зору чистоти.

Хоча для виконання потрібен смішний час, я виявив, що тестування на наявність конкретних файлів також дає хороші та швидші результати, оскільки я не посилаюсь на виконуваний файл:

Тому,

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

просто використовує швидку перевірку наявності файлу Bash. Оскільки я зараз в Windows, я не можу сказати вам про конкретні файли для Linuxes та Mac OS X з моєї голови, але я впевнений, що вони існують. :-)


-3

Використовувати лише це з командного рядка дуже добре, завдяки Джастіну:

#!/bin/bash

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

OS=`uname`
echo "$OS"

джерело


Що нового у вашому сценарії?
mallaudin
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.