Wie erkennt man das Betriebssystem von einem Bash-Skript?

Ich möchte meine .bashrc und .bash_login Dateien in Versionskontrolle behalten, damit ich sie zwischen allen Computern verwenden kann, die ich verwende. Das Problem ist, dass ich einige OS-spezifische Aliase habe, also suchte ich nach einer Möglichkeit festzustellen, ob das Skript unter Mac OS X, Linux oder Cygwin läuft.

Was ist der richtige Weg, um das Betriebssystem in einem Bash– Skript zu erkennen?

    Für meine .bashrc verwende ich den folgenden Code:

     platform='unknown' unamestr=`uname` if [[ "$unamestr" == 'Linux' ]]; then platform='linux' elif [[ "$unamestr" == 'FreeBSD' ]]; then platform='freebsd' fi 

    Dann mache ich etwas wie:

     if [[ $platform == 'linux' ]]; then alias ls='ls --color=auto' elif [[ $platform == 'freebsd' ]]; then alias ls='ls -G' fi 

    Es ist hässlich, aber es funktioniert. Sie können case statt verwenden, wenn Sie bevorzugen.

    Die Bash-Manpage besagt, dass die Variable OSTYPE den Namen des Betriebssystems speichert:

    OSTYPE automatisch auf eine Zeichenfolge gesetzt, die das Betriebssystem beschreibt, auf dem bash ausgeführt wird. Der Standardwert ist systemabhängig.

    Es ist hier auf linux-gnu .

    Ich denke, das Folgende sollte funktionieren. Ich bin mir aber über win32 nicht sicher.

     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 

    Sie können einfach die vordefinierte Variable $ OSTYPE verwenden, zB:

     case "$OSTYPE" in solaris*) echo "SOLARIS" ;; darwin*) echo "OSX" ;; linux*) echo "LINUX" ;; bsd*) echo "BSD" ;; msys*) echo "WINDOWS" ;; *) echo "unknown: $OSTYPE" ;; esac 

    Eine andere Methode besteht darin, eine Plattform basierend auf dem Befehl uname zu erkennen.

    Sehen Sie sich das folgende Skript an (bereit für die Aufnahme in .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 

    Sie können ein praktisches Beispiel in meiner .bashrc .

    Das Erkennen von Betriebssystem und CPU-Typ ist nicht so einfach portabel zu machen. Ich habe ein sh Skript von etwa 100 Zeilen, das auf den unterschiedlichsten Unix-Plattformen funktioniert: jedes System, das ich seit 1988 benutzt habe.

    Die Schlüsselelemente sind

    • uname -p ist ein processortyp , ist aber normalerweise auf modernen Unix-Plattformen unknown .

    • uname -m gibt auf einigen Unix-Systemen den “Hardware-Namen der Maschine” an.

    • /bin/arch , wenn es existiert, gibt normalerweise den Typ des processors an.

    • uname ohne Argumente nennt das Betriebssystem.

    Schließlich müssen Sie über die Unterschiede zwischen den Plattformen nachdenken und überlegen, wie gut Sie diese machen wollen. Zum Beispiel, um die Dinge einfach zu halten, behandle ich i386 über i686 , jeden ” Pentium* ” und jeden ” AMD*Athlon* ” alle als x86 .

    My ~/.profile führt beim Start ein Skript aus, das eine Variable auf eine Zeichenfolge setzt, die die Kombination von CPU und Betriebssystem angibt. Ich habe plattformspezifische bin , man , lib und include Verzeichnisse, die darauf basieren. Dann habe ich eine Menge Umgebungsvariablen gesetzt. So kann beispielsweise ein Shell-Skript zum Neuformatieren von E-Mails zB $LIB/mailfmt was eine plattformspezifische ausführbare Binärdatei ist.

    Wenn Sie Ecken ausschneiden möchten , geben uname -m und plain uname an, was Sie auf vielen Plattformen wissen möchten. Fügen Sie andere Sachen hinzu, wenn Sie sie brauchen. (Und Use case , nicht verschachtelt if !)

    Ich empfehle, diesen vollständigen Bash-Code zu verwenden

     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 

    Weitere Beispiele finden Sie hier: https://github.com/coto/server-easy-install/blob/master/lib/core.sh

    In bash, verwenden Sie $OSTYPE und $HOSTTYPE , wie dokumentiert; das ist was ich mache. Wenn das nicht genug ist, und wenn sogar uname oder uname -a (oder andere geeignete Optionen) nicht genug Informationen liefert, gibt es immer das config.guess- Skript aus dem GNU-Projekt, das genau für diesen Zweck erstellt wurde.

    Versuchen Sie es mit “Uname”. Zum Beispiel in Linux: “uname -a”.

    Laut der Handbuchseite stimmt uname mit SVr4 und POSIX überein, also sollte es auch auf Mac OS X und Cygwin verfügbar sein, aber das kann ich nicht bestätigen.

    BTW: $ OSTYPE ist hier auch auf linux-gnu gnu gesetzt 🙂

    Ich würde vorschlagen, einige dieser Antworten zu vermeiden. Vergessen Sie nicht, dass Sie andere Formen des Zeichenfolgenvergleichs wählen können, die die meisten Varianten oder den angebotenen hässlichen Code auflösen würden.

    Eine solche Lösung wäre eine einfache Überprüfung, z.

    if [[ "$OSTYPE" =~ ^darwin ]]; then

    Dies hat den zusätzlichen Vorteil, dass jede Version von Darwin trotz des Versions-Suffix angepasst werden kann. Dies funktioniert auch für alle Variationen von Linux man erwarten kann.

    Sie können hier einige zusätzliche Beispiele in meinen dotfiles sehen

     uname 

    oder

     uname -a 

    wenn Sie mehr Informationen wünschen

    Ich habe ein persönliches Bash-Bibliotheks- und Skript-Framework geschrieben , das GNU Shtool verwendet , um eine ziemlich genaue Plattformerkennung durchzuführen .

    GNU shtool ist ein sehr portabler Satz von Skripten, der unter anderem den Befehl ‘shtool platform’ enthält. Hier ist die Ausgabe von:

     shtool platform -v -F "%sc (%ac) %st (%at) %sp (%ap)" 

    auf ein paar verschiedenen Maschinen:

     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) 

    Dies führt zu ziemlich zufriedenstellenden Ergebnissen, wie Sie sehen können. GNU shtool ist ein wenig langsam, also speichere und aktualisiere ich die Plattformidentifikation in einer Datei auf dem System, das meine Skripte aufrufen. Es ist mein Rahmen, das funktioniert für mich, aber Ihre Laufleistung kann variieren.

    Jetzt müssen Sie eine Möglichkeit finden, Shtool mit Ihren Skripten zu packen, aber es ist keine harte Übung. Sie können immer auch auf die Ausgabe von uname zurückgreifen.

    BEARBEITEN:

    Ich habe den Beitrag von Teddy über config.guess (irgendwie) verpasst. Dies sind sehr ähnliche Skripte, aber nicht dasselbe. Ich persönlich benutze Shtool auch für andere Zwecke, und es hat sehr gut für mich funktioniert.

    Ich habe diese Zucker in meinem .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" ]]; } 

    Also kann ich Sachen machen wie:

     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" 

    Dies sollte auf allen Distributionen sicher sein.

     $ cat /etc/*release 

    Das erzeugt so etwas.

      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/" 

    Extrahieren / Zuweisen von Variablen wie gewünscht

    Hinweis: Bei einigen Setups. Dies kann Ihnen auch einige Fehler geben, die Sie ignorieren können.

      cat: /etc/upstream-release: Is a directory 

    Im Folgenden wird ein Ansatz zur Erkennung von Debian und RedHat-basierten Linux-Betriebssystemen unter Verwendung der Datei / etc / lsb-release und / etc / os-release (abhängig von der von Ihnen verwendeten Linux -Version ) vorgestellt.

     #!/bin/bash set -e YUM_PACKAGE_NAME="python python-devl python-pip openssl-devel" DEB_PACKAGE_NAME="python2.7 python-dev python-pip libssl-dev" if cat /etc/*release | grep ^NAME | grep CentOS; then echo "===============================================" echo "Installing packages $YUM_PACKAGE_NAME on CentOS" echo "===============================================" yum install -y $YUM_PACKAGE_NAME elif cat /etc/*release | grep ^NAME | grep Red; then echo "===============================================" echo "Installing packages $YUM_PACKAGE_NAME on RedHat" echo "===============================================" yum install -y $YUM_PACKAGE_NAME elif cat /etc/*release | grep ^NAME | grep Fedora; then echo "================================================" echo "Installing packages $YUM_PACKAGE_NAME on Fedorea" echo "================================================" yum install -y $YUM_PACKAGE_NAME elif cat /etc/*release | grep ^NAME | grep Ubuntu; then echo "===============================================" echo "Installing packages $DEB_PACKAGE_NAME on Ubuntu" echo "===============================================" apt-get update apt-get install -y $DEB_PACKAGE_NAME elif cat /etc/*release | grep ^NAME | grep Debian ; then echo "===============================================" echo "Installing packages $DEB_PACKAGE_NAME on Debian" echo "===============================================" apt-get update apt-get install -y $DEB_PACKAGE_NAME elif cat /etc/*release | grep ^NAME | grep Mint ; then echo "=============================================" echo "Installing packages $DEB_PACKAGE_NAME on Mint" echo "=============================================" apt-get update apt-get install -y $DEB_PACKAGE_NAME elif cat /etc/*release | grep ^NAME | grep Knoppix ; then echo "=================================================" echo "Installing packages $DEB_PACKAGE_NAME on Kanoppix" echo "=================================================" apt-get update apt-get install -y $DEB_PACKAGE_NAME else echo "OS NOT DETECTED, couldn't install package $PACKAGE" exit 1; fi exit 0 

    Ausgabebeispiel für Ubuntu Linux:

     delivery@delivery-E5450$ sudo sh detect_os.sh [sudo] password for delivery: NAME="Ubuntu" =============================================== Installing packages python2.7 python-dev python-pip libssl-dev on Ubuntu =============================================== Ign http://dl.google.com stable InRelease Get:1 http://dl.google.com stable Release.gpg [916 B] Get:2 http://dl.google.com stable Release [1.189 B] ... 

    Sie können Folgendes verwenden:

     OS=$(uname -s) 

    Dann können Sie in Ihrem Skript die Betriebssystemvariable verwenden.

    Die folgenden Schritte halfen, die Überprüfung für ubuntu korrekt durchzuführen:

     if [[ "$OSTYPE" =~ ^linux ]]; then sudo apt-get install  fi 

    Ich neige dazu, meine .bashrc und .bash_alias auf einer Dateifreigabe zu behalten, auf die alle Plattformen zugreifen können. So bezwinge ich das Problem in meiner .bash_alias:

     if [[ -f (name of share)/.bash_alias_$(uname) ]]; then . (name of share)/.bash_alias_$(uname) fi 

    Und ich habe zum Beispiel ein .bash_alias_Linux mit:

     alias ls='ls --color=auto' 

    Auf diese Weise halte ich plattformspezifischen und portablen Code getrennt, Sie können dasselbe für .bashrc tun

    Sie können die folgende if-Klausel verwenden und sie bei Bedarf erweitern:

     if [ "${OSTYPE//[0-9.]/}" == "darwin" ] then aminute_ago="-v-1M" elif [ "${OSTYPE//[0-9.]/}" == "linux-gnu" ] then aminute_ago="-d \"1 minute ago\"" fi 

    Ich habe die obigen Nachrichten über ein paar Linux-Distributionen ausprobiert und festgestellt, dass das Folgende am besten für mich funktioniert. Es ist eine kurze, prägnante exakte Wortantwort, die auch unter Windows für Bash funktioniert.

     OS=$(cat /etc/*release | grep ^NAME | tr -d 'NAME="') #$ echo $OS # Ubuntu