Как проверить, работает ли в Cygwin, Mac или Linux?

334

У меня есть сценарий оболочки, который используется как на Windows / Cygwin и Mac и Linux. Для каждой версии нужны немного разные переменные.

Как скрипт shell / bash может определить, запущен ли он в Cygwin, на Mac или в Linux?

bastibe
источник

Ответы:

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).

paxdiablo
источник
11
Иногда меньше - больше;) Кстати, в Википедии есть таблица с примерами вывода uname по адресу en.wikipedia.org/wiki/Uname
schot
Вывод Git Bash uname -s на Windows 7 есть MINGW32_NT-6.1. Кроме того, нет /cygdriveпрефикса, только /cдля C:.
ColinM
7
Git Bash не Cygwin. Это MinGW, минимальный GNU для MS Windows, поэтому поведение отличается.
Бойд Стивен Смит-младший
Я продвинул другой ответ, потому что этот ответ не имеет отношения к части OP, How can a shell/bash script detect ...а другой делает.
Джесси Чисхолм
Если я запускаю скрипт под cygwin, выполняя "\ cygwin64 \ bin \ bash -c scriptname", это не обязательно работает. В этой ситуации путь cygwin не устанавливается и в uname -sитоге вызывает все, что unameнаходится на вашем текущем пути, что в моей системе оказывается версией, установленной для gedaвозврата текста WindowsNT. Это может быть версия MinGW, как описано выше. Надежное обнаружение Cygwin не должно полагаться на путь, установленный надлежащим образом, IMO. Таким образом, $(uname -s)следует изменить, $(/bin/uname -s)чтобы обнаружить Cygwin.
Жюль
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, Kernel 3.2.0) протестирован.
  • OS X (10.6.8 Snow Leopard) протестирована нормально.
  • Windows (64-битная Windows 7) протестирована.

Что я выучил

  1. Проверьте как открывающие, так и закрывающие котировки.
  2. Проверить отсутствие скобок и скобок {}

Ссылки

Альберт
источник
Для MinGW, это может сделать больше смысла , чтобы проверить: [ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ].
Ачал Дейв
2
@ Альберт: выражение "$(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
OpenBSD OpenBSD
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
источник
3
Недурно для Solaris и исследований выше.
okutane
Привет, @okutane. Я не понимаю что ты имеешь в виду. Пожалуйста, предоставьте больше деталей. Вы предлагаете что-нибудь? Приветствия
olibre
3
Я голосую, вот и все.
okutane
1
Это именно то, что я искал, чтобы написать переносимый / кроссплатформенный ~/.profile(чтобы установить переменные среды, такие как $PATH- комментирование, чтобы обеспечить ключевые слова для поиска потомков).
Брахам Снайдер
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 добавляет номер версии ОС после «darwin». Мне говорят, что значение win на самом деле равно win32, может быть, есть win64?

Возможно, мы могли бы работать вместе, чтобы заполнить таблицу проверенных значений здесь:

  • Linux Ubuntu (включая WSL ):linux-gnu
  • Cygwin 64-bit: 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 automake для всех доступных типов.
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 первых символов uname -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
}

Я использую это в моих точечных файлах

Wener
источник
2

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

Вся информация, которая вам когда-либо понадобится. Google твой друг.

Используйте uname -sдля запроса имени системы.

  • Mac: Darwin
  • Cygwin: CYGWIN_...
  • Linux: разнообразный, LINUXдля большинства
rubenvb
источник
2

Подсистема Windows для Linux не существовала, когда задавался этот вопрос. Это дало эти результаты в моем тесте:

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

Это означает, что вам нужен uname -r, чтобы отличить его от родного Linux.

Туман
источник
1
К сожалению, Mingw-w64 выдает точно так же.
Туман
1

Я полагаю, что uname ответ непобедим, в основном с точки зрения чистоты.

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

Так,

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

просто использует быструю проверку наличия файла Bash. Поскольку я сейчас нахожусь на Windows, я не могу сказать вам какие-либо конкретные файлы для Linux и Mac OS X, но я почти уверен, что они существуют. :-)

Чарльз Роберто Канато
источник
-3

Использование только этого из командной строки работает очень хорошо, благодаря Джастину:

#!/bin/bash

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

OS=`uname`
echo "$OS"

источник

lizardhr
источник
Что нового в вашем сценарии?
Маллаудин