ฉันมีเชลล์สคริปต์ที่ใช้ทั้งบน 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.17 นอกจากนี้ยังไม่มี/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)exprunameunameเพื่อรับข้อมูลระบบ ( -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 -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
~/.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-gnucygwinmsys(โปรดเพิ่มมูลค่าของคุณต่อท้ายหากแตกต่างจากรายการที่มีอยู่)
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.exeC:\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เพื่อสืบค้นชื่อระบบ
DarwinCYGWIN_...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"