Programing

Bash 스크립트에서 OS를 감지하는 방법은 무엇입니까?

lottogame 2020. 2. 16. 19:12
반응형

Bash 스크립트에서 OS를 감지하는 방법은 무엇입니까?


내가 사용하는 모든 컴퓨터에서 사용할 수 있도록 파일 .bashrc.bash_login파일을 버전 관리 상태로 유지하고 싶습니다 . 문제는 일부 OS 관련 별칭이 있으므로 스크립트가 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에 운영 체제 이름이 저장되어 있다고 나와 있습니다.

OSTYPEbash가 실행중인 운영 체제를 설명하는 문자열로 자동 설정됩니다. 기본값은 시스템에 따라 다릅니다.

여기로 설정되어 linux-gnu있습니다.


$OSTYPE

미리 정의 된 $OSTYPE변수를 간단히 사용할 수 있습니다 . 예 :

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

그러나 이전 쉘 (예 : Bourne shell ) 에서는 인식되지 않습니다 .


uname

또 다른 방법은 uname명령을 기반으로 플랫폼을 감지하는 것 입니다.

다음 스크립트를 참조하십시오 (.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

내 실제 사례를 찾을 수 있습니다.bashrc .


Travis CI에 사용 된 유사한 버전은 다음과 같습니다 .

case $(uname | tr '[:upper:]' '[:lower:]') in
  linux*)
    export TRAVIS_OS_NAME=linux
    ;;
  darwin*)
    export TRAVIS_OS_NAME=osx
    ;;
  msys*)
    export TRAVIS_OS_NAME=windows
    ;;
  *)
    export TRAVIS_OS_NAME=notset
    ;;
esac

검출 운영 체제 및 CPU 타입은 너무 쉽게 할 수없는 이식 . 나는 sh매우 다양한 Unix 플랫폼에서 작동하는 약 100 줄 스크립트를 가지고 있습니다 : 1988 년 이래로 사용한 시스템.

핵심 요소는

  • uname -p입니다 프로세서 유형 하지만 일반적으로 unknown현대 유닉스 플랫폼에서.

  • uname -m 일부 유닉스 시스템에서 "기계 하드웨어 이름"을 제공합니다.

  • /bin/arch존재하는 경우 일반적으로 프로세서 유형을 제공합니다.

  • uname 인수가 없으면 운영 체제 이름이 지정됩니다.

결국 플랫폼 간의 차이점과 플랫폼을 얼마나 잘 만들고 싶어하는지 생각 해야합니다. 예를 들어, 단지 물건을 간단하게 유지하기 위해, 나는 치료 i386를 통해 i686, 어떤 " Pentium*"및 " AMD*Athlon*"모든으로 x86.

~/.profile시작시 스크립트를 실행하여 하나의 변수를 CPU와 운영 체제의 조합을 나타내는 문자열로 설정합니다. 나는 플랫폼 별이가 bin, man, lib, 및 include설정받을 디렉토리를 그 기반으로. 그런 다음 환경 변수의 보트로드를 설정했습니다. 예를 들어, 메일을 재 포맷하기위한 쉘 스크립트는 예를 들어 $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예상 되는 모든 변형에 적용 됩니다.

당신은 내 dotfiles 내에서 몇 가지 추가 예제를 볼 수 있습니다 여기에


나는이 설탕을 내 .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

더 많은 정보를 원한다면


내가 쓴 개인 배쉬 라이브러리와 스크립트 프레임 워크를 사용하는 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 출력으로 넘어갈 수 있습니다.

편집하다:

Teddy가 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

아래 / etc / lsb-release/ etc / os-release (사용중인 Linux 버전 에 따라 다름)를 사용 하는 Debian 및 RedHat 기반 Linux OS 를 감지 하고 이를 기반으로 간단한 조치를 취하는 방법입니다.

#!/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

출력 예를 위한 우분투 리눅스 :

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

다음 if 절을 사용하고 필요에 따라 확장 할 수 있습니다.

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

모든 플랫폼이 액세스 할 수있는 파일 공유에 .bashrc 및 .bash_alias를 유지하는 경향이 있습니다. 이것이 .bash_alias에서 문제를 극복하는 방법입니다.

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

그리고 예를 들어 .bash_alias_Linux가 있습니다.

alias ls='ls --color=auto'

이렇게하면 플랫폼 특정 코드와 이식 가능한 코드를 별도로 유지하므로 .bashrc에 대해 동일한 작업을 수행 할 수 있습니다


다음을 수행하면 우분투 검사를 올바르게 수행하는 데 도움이되었습니다.

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

몇 가지 Linux 배포판에서 위의 메시지를 시도한 결과 다음과 같은 것이 가장 효과적입니다. Windows의 Bash에서도 작동하는 짧고 간결한 정확한 단어 답변입니다.

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

known리눅스 배포판이 Debian 또는 Ubunu인지 확인하기 위해 많은 파일을 확인한 다음 기본값을 $OSTYPE변수로 지정합니다.

os='Uknown'
unamestr="${OSTYPE//[0-9.]/}"
os=$( compgen -G "/etc/*release" > /dev/null  && cat /etc/*release | grep ^NAME | tr -d 'NAME="'  ||  echo "$unamestr")

echo "$os"

이 시도:

DISTRO=$(cat /etc/*-release | grep -w NAME | cut -d= -f2 | tr -d '"')
echo "Determined platform: $DISTRO"

참고 URL : https://stackoverflow.com/questions/394230/how-to-detect-the-os-from-a-bash-script



반응형