ฉันมีเชลล์สคริปต์ที่ใช้ทั้งบน Windows / Cygwin และ Mac และ Linux มันต้องการตัวแปรที่แตกต่างกันเล็กน้อยสำหรับแต่ละรุ่น
สคริปต์ shell / bash ตรวจพบได้อย่างไรว่าทำงานอยู่ใน Cygwin, บน Mac หรือใน Linux?
ฉันมีเชลล์สคริปต์ที่ใช้ทั้งบน Windows / Cygwin และ Mac และ Linux มันต้องการตัวแปรที่แตกต่างกันเล็กน้อยสำหรับแต่ละรุ่น
สคริปต์ shell / bash ตรวจพบได้อย่างไรว่าทำงานอยู่ใน Cygwin, บน Mac หรือใน Linux?
คำตอบ:
โดยปกติ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
)
MINGW32_NT-6.1
7 นอกจากนี้ยังไม่มี/cygdrive
คำนำหน้าเพียงสำหรับ/c
C:
How can a shell/bash script detect ...
และอีกคำตอบคือ
uname -s
จบลงด้วยการเรียกสิ่งที่uname
เป็นครั้งแรกในเส้นทางปัจจุบันของคุณซึ่งในระบบของฉันเปลี่ยนจากการมีเวอร์ชันที่ติดตั้งด้วยซึ่งจะส่งกลับข้อความgeda
WindowsNT
แม้ว่าอาจเป็นรุ่น MinGW อย่างเท่าเทียมกันตามที่อธิบายไว้ข้างต้น การตรวจจับที่เชื่อถือได้สำหรับ cygwin จะต้องไม่พึ่งพาเส้นทางที่ตั้งไว้อย่างเหมาะสม IMO ดังนั้น$(uname -s)
ควรเปลี่ยน$(/bin/uname -s)
เป็นตรวจจับ cygwin
#!/usr/bin/env bash
แทน#!/bin/sh
เพื่อป้องกันปัญหาที่เกิดจากการ/bin/sh
เชื่อมโยงไปยังเชลล์เริ่มต้นที่แตกต่างกันในแพลตฟอร์มที่แตกต่างกันหรือจะมีข้อผิดพลาดเช่นตัวดำเนินการที่ไม่คาดคิดนั่นคือสิ่งที่เกิดขึ้นบนคอมพิวเตอร์ของฉัน (Ubuntu 64 บิต 12.04)expr
uname
uname
เพื่อรับข้อมูลระบบ ( -s
พารามิเตอร์)expr
และsubstr
จัดการกับสตริงif
elif
fi
สำหรับทำงานจับคู่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
[ "$(expr substr $(uname -s) 1 10)" == "MINGW32_NT" ]
ก็อาจทำให้รู้สึกมากขึ้นในการตรวจสอบ:
"$(expr substr $(uname -s) 1 5)"
เป็นบิตแปลก if [ `uname -s` == CYGWIN* ]; then
มีวิธีการที่สวยมากขึ้นที่จะทำเช่นนี้คือ: อ่าน: ถ้าuname -s
เริ่มต้นด้วยCYGWINแล้ว ...
if [[ $(uname -s) == CYGWIN* ]]; then
uname -s
จะให้สิ่งอื่นที่ไม่ใช่ "Linux" หรือไม่?
การใช้งาน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
โปรดช่วยทำให้เป็นปัจจุบัน (แก้ไขคำตอบหรือโพสต์ความคิดเห็น) คุณสามารถอัปเดตบทความ 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
~/.profile
(เพื่อตั้งค่าตัวแปรสภาพแวดล้อมเช่น$PATH
- แสดงความคิดเห็นเพื่อให้คำค้นหาสำหรับลูกหลาน)
uname -sr
และเปรียบเทียบกับก่อนLinux*Microsoft)
Linux*)
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-gnu
cygwin
msys
(โปรดเพิ่มมูลค่าของคุณต่อท้ายหากแตกต่างจากรายการที่มีอยู่)
env | grep OSTYPE
แต่คุณจะเห็นมันภายใต้set | grep OSTYPE
OSTYPE
ตัวแปร(conftypes.h)มีการกำหนดค่าเวลาที่สร้างโดยใช้สำเนาถูกต้องของ automake ของOS
ตัวแปร(Makefile.in) หนึ่งอาจศึกษาไฟล์lib / config.subของ automake สำหรับประเภทที่มีทั้งหมด
เพื่อสร้างตามคำตอบของ 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.exe
C:\Windows\system32\cmd.exe
# 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
ดูดีขึ้นและทำงานเหมือนเดิม
[[ $(uname -s) == CYGWIN* ]]
. [[ $(uname -s) =~ ^CYGWIN* ]]
ยังทราบว่าการแสดงออกปกติขยายมีความแม่นยำมากขึ้นในกรณีของเรา:
expr substr $(uname -s) 1 6
ให้ข้อผิดพลาด ( expr: syntax error
) กับ macOS
ตกลงนี่เป็นวิธีของฉัน
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ของฉัน
http://en.wikipedia.org/wiki/Uname
ข้อมูลทั้งหมดที่คุณต้องการ Google คือเพื่อนของคุณ
ใช้uname -s
เพื่อสืบค้นชื่อระบบ
Darwin
CYGWIN_...
LINUX
ที่สุดWindows Subsystem สำหรับ Linux ไม่มีอยู่เมื่อมีการถามคำถามนี้ มันให้ผลลัพธ์เหล่านี้ในการทดสอบของฉัน:
uname -s -> Linux
uname -o -> GNU/Linux
uname -r -> 4.4.0-17763-Microsoft
ซึ่งหมายความว่าคุณต้องการ uname -r เพื่อแยกความแตกต่างจาก native Linux
ฉันเดาว่าคำตอบที่ไม่มีชื่อเป็นสิ่งที่เอาชนะได้ส่วนใหญ่ในแง่ของความสะอาด
แม้ว่าจะต้องใช้เวลาในการดำเนินการที่น่าขัน แต่ฉันพบว่าการทดสอบไฟล์ที่มีอยู่นั้นยังให้ผลลัพธ์ที่ดีและรวดเร็วกว่าด้วยเนื่องจากฉันไม่ได้เรียกใช้ไฟล์ปฏิบัติการ:
ดังนั้น,
[ -f /usr/bin/cygwin1.dll ] && echo Yep, Cygwin running
เพียงใช้การตรวจสอบสถานะไฟล์ Bash อย่างรวดเร็ว ตอนนี้ฉันใช้ Windows ฉันไม่สามารถบอกไฟล์เฉพาะสำหรับ Linux และ Mac OS X จากหัวของฉันได้ แต่ฉันค่อนข้างมั่นใจว่ามันมีอยู่จริง :-)
ใช้สิ่งนี้จากบรรทัดคำสั่งทำงานได้ดีมากขอบคุณ Justin:
#!/bin/bash
################################################## #########
# Bash script to find which OS
################################################## #########
OS=`uname`
echo "$OS"