我想保留我.bashrc
和.bash_login
文件的版本控制,以便我可以在我使用的所有计算机之间使用它们.问题是,我有一些特定于操作系统的别名,所以我一直在寻找一种方式来确定脚本在Mac OS X,Linux或运行Cygwin的.
在Bash脚本中检测操作系统的正确方法是什么?
我认为以下内容应该有效.我不确定win32
.
if [[ "$OSTYPE" == "linux-gnu" ]]; then # ... elif [[ "$OSTYPE" == "darwin"* ]]; then # Mac OSX elif [[ "$OSTYPE" == "cygwin" ]]; then # POSIX compatibility layer and Linux environment emulation for Windows elif [[ "$OSTYPE" == "msys" ]]; then # Lightweight shell and GNU utilities compiled for Windows (part of MinGW) elif [[ "$OSTYPE" == "win32" ]]; then # I'm not sure this can happen. elif [[ "$OSTYPE" == "freebsd"* ]]; then # ... else # Unknown. fi
对于我的.bashrc,我使用以下代码:
platform='unknown' unamestr=`uname` if [[ "$unamestr" == 'Linux' ]]; then platform='linux' elif [[ "$unamestr" == 'FreeBSD' ]]; then platform='freebsd' fi
然后我做的事情如下:
if [[ $platform == 'linux' ]]; then alias ls='ls --color=auto' elif [[ $platform == 'freebsd' ]]; then alias ls='ls -G' fi
这很难看,但它确实有效.如果您愿意,可以使用case
而不是if
.
bash手册页说变量OSTYPE存储操作系统的名称:
OSTYPE
自动设置为描述正在执行bash的操作系统的字符串.默认值取决于系统.
它设置在linux-gnu
这里.
您可以简单地使用预定义的$ OSTYPE变量即:
case "$OSTYPE" in solaris*) echo "SOLARIS" ;; darwin*) echo "OSX" ;; linux*) echo "LINUX" ;; bsd*) echo "BSD" ;; msys*) echo "WINDOWS" ;; *) echo "unknown: $OSTYPE" ;; esac
另一种方法是基于$OSTYPE
命令检测平台.
请参阅以下脚本(准备包含在.bashrc中):
# Detect the platform (similar to $OSTYPE) OS="`uname`" case $OS in 'Linux') OS='Linux' alias ls='ls --color=auto' ;; 'FreeBSD') OS='FreeBSD' alias ls='ls -G' ;; 'WindowsNT') OS='Windows' ;; 'Darwin') OS='Mac' ;; 'SunOS') OS='Solaris' ;; 'AIX') ;; *) ;; esac
你可以在我的一些实际例子$OSTYPE
.
检测操作系统和CPU类型并不容易移植.我有一个sh
大约100行的脚本,适用于各种各样的Unix平台:自1988年以来我使用过的任何系统.
关键要素是
uname -p
是处理器类型,但通常unknown
在现代Unix平台上.
uname -m
将在某些Unix系统上提供"机器硬件名称".
/bin/arch
,如果它存在,通常会给出处理器的类型.
uname
没有参数将命名操作系统.
最终,您将不得不考虑平台之间的区别以及您想要制作它们的精确程度. 例如,只是为了让事情变得简单,我把i386
通过i686
,任何" Pentium*
"任何" AMD*Athlon*
"所有的x86
.
我~/.profile
在启动时运行一个脚本,它将一个变量设置为一个字符串,表示CPU和操作系统的组合.我有特定于平台的bin
,man
,lib
,和include
基于该是那些获得建立目录.然后我设置了一大堆环境变量.因此,例如,重新格式化邮件的shell脚本可以调用,例如,$LIB/mailfmt
这是特定于平台的可执行二进制文件.
如果你想偷工减料,那么uname -m
普通话uname
会告诉你在许多平台上你想知道什么.在需要时添加其他东西.(并使用case
,而不是嵌套if
!)
我建议使用这个完整的bash代码
lowercase(){ echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/" } OS=`lowercase \`uname\`` KERNEL=`uname -r` MACH=`uname -m` if [ "{$OS}" == "windowsnt" ]; then OS=windows elif [ "{$OS}" == "darwin" ]; then OS=mac else OS=`uname` if [ "${OS}" = "SunOS" ] ; then OS=Solaris ARCH=`uname -p` OSSTR="${OS} ${REV}(${ARCH} `uname -v`)" elif [ "${OS}" = "AIX" ] ; then OSSTR="${OS} `oslevel` (`oslevel -r`)" elif [ "${OS}" = "Linux" ] ; then if [ -f /etc/redhat-release ] ; then DistroBasedOn='RedHat' DIST=`cat /etc/redhat-release |sed s/\ release.*//` PSUEDONAME=`cat /etc/redhat-release | sed s/.*\(// | sed s/\)//` REV=`cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//` elif [ -f /etc/SuSE-release ] ; then DistroBasedOn='SuSe' PSUEDONAME=`cat /etc/SuSE-release | tr "\n" ' '| sed s/VERSION.*//` REV=`cat /etc/SuSE-release | tr "\n" ' ' | sed s/.*=\ //` elif [ -f /etc/mandrake-release ] ; then DistroBasedOn='Mandrake' PSUEDONAME=`cat /etc/mandrake-release | sed s/.*\(// | sed s/\)//` REV=`cat /etc/mandrake-release | sed s/.*release\ // | sed s/\ .*//` elif [ -f /etc/debian_version ] ; then DistroBasedOn='Debian' DIST=`cat /etc/lsb-release | grep '^DISTRIB_ID' | awk -F= '{ print $2 }'` PSUEDONAME=`cat /etc/lsb-release | grep '^DISTRIB_CODENAME' | awk -F= '{ print $2 }'` REV=`cat /etc/lsb-release | grep '^DISTRIB_RELEASE' | awk -F= '{ print $2 }'` fi if [ -f /etc/UnitedLinux-release ] ; then DIST="${DIST}[`cat /etc/UnitedLinux-release | tr "\n" ' ' | sed s/VERSION.*//`]" fi OS=`lowercase $OS` DistroBasedOn=`lowercase $DistroBasedOn` readonly OS readonly DIST readonly DistroBasedOn readonly PSUEDONAME readonly REV readonly KERNEL readonly MACH fi fi
这里有更多示例:https://github.com/coto/server-easy-install/blob/master/lib/core.sh
在bash中,使用$OSTYPE
和$HOSTTYPE
记录; 这就是我做的.如果这还不够,如果偶数uname
或uname -a
(或其他适当的选项)没有提供足够的信息,那么GNU项目中的config.guess脚本总是完全用于此目的.
尝试使用"uname".例如,在Linux中:"uname -a".
根据手册页,uname符合SVr4和POSIX,因此它也应该在Mac OS X和Cygwin上可用,但我无法确认.
BTW:$ OSTYPE也设置在linux-gnu
这里:)
我建议避免一些这些答案.不要忘记您可以选择其他形式的字符串比较,这将清除大多数变体或提供的丑陋代码.
一个这样的解决方案是简单的检查,例如:
if [[ "$OSTYPE" =~ ^darwin ]]; then
除了版本后缀之外,它还具有匹配任何版本的Darwin的额外好处.这也适用于Linux
人们可能期望的任何变化.
你可以看到我的点文件中的一些附加的例子在这里
我在这里写了这些糖.bashrc
:
if_os () { [[ $OSTYPE == *$1* ]]; } if_nix () { case "$OSTYPE" in *linux*|*hurd*|*msys*|*cygwin*|*sua*|*interix*) sys="gnu";; *bsd*|*darwin*) sys="bsd";; *sunos*|*solaris*|*indiana*|*illumos*|*smartos*) sys="sun";; esac [[ "${sys}" == "$1" ]]; }
所以我可以这样做:
if_nix gnu && alias ls='ls --color=auto' && export LS_COLORS="..." if_nix bsd && export CLICOLORS=on && export LSCOLORS="..." if_os linux && alias psg="ps -FA | grep" #alternative to pgrep if_nix bsd && alias psg="ps -alwx | grep -i" #alternative to pgrep if_os darwin && alias finder="open -R"
uname
要么
uname -a
如果你想了解更多信息
我编写了一个个人Bash库和脚本框架,它使用GNU shtool进行相当准确的平台检测.
GNU shtool是一组非常便携的脚本,除了其他有用的东西之外,还包含'shtool platform'命令.这是输出:
shtool platform -v -F "%sc (%ac) %st (%at) %sp (%ap)"
在几台不同的机器上:
Mac OS X Leopard: 4.4BSD/Mach3.0 (iX86) Apple Darwin 9.6.0 (i386) Apple Mac OS X 10.5.6 (iX86) Ubuntu Jaunty server: LSB (iX86) GNU/Linux 2.9/2.6 (i686) Ubuntu 9.04 (iX86) Debian Lenny: LSB (iX86) GNU/Linux 2.7/2.6 (i686) Debian GNU/Linux 5.0 (iX86)
如您所见,这会产生非常令人满意的结果.GNU shtool有点慢,所以我实际上将平台标识存储并更新到我的脚本调用的系统上的文件中.这是我的框架,所以对我有用,但你的里程可能会有所不同.
现在,您必须找到一种方法来使用脚本打包shtool,但这不是一项艰苦的练习.你也总是可以依靠uname输出.
编辑:
我错过了泰迪的帖子config.guess
(某种程度上).这些是非常相似的脚本,但不一样.我个人也将shtool用于其他用途,它对我来说一直很好用.
您可以使用以下内容:
OS=$(uname -s)
然后您可以在脚本中使用OS变量.
这应该可以安全地用于所有发行版.
$ cat /etc/*release
这产生了这样的东西.
DISTRIB_ID=LinuxMint DISTRIB_RELEASE=17 DISTRIB_CODENAME=qiana DISTRIB_DESCRIPTION="Linux Mint 17 Qiana" NAME="Ubuntu" VERSION="14.04.1 LTS, Trusty Tahr" ID=ubuntu ID_LIKE=debian PRETTY_NAME="Ubuntu 14.04.1 LTS" VERSION_ID="14.04" HOME_URL="http://www.ubuntu.com/" SUPPORT_URL="http://help.ubuntu.com/" BUG_REPORT_URL="http://bugs.launchpad.net/ubuntu/"
根据需要提取/分配变量
注意:在某些设置上.这也可能会给您一些您可以忽略的错误.
cat: /etc/upstream-release: Is a directory