システムパッケージマネージャの識別

システムパッケージマネージャの識別

デフォルトのシステムパッケージマネージャを識別する方法(スクリプトから)はありますか?

明確にすると、私がやりたいことは与えられたコマンドを実行することです。 Debianやその派生物では「apt」のようなものを返し、openSUSEでは「zypp」を返し、Fedoraなどでは「yum」を返します。 Arch Linuxは「pacman」などを返します。

以下の方法でこれを行うことができます。同じ名前の実行可能ファイルがある限り、中断されないより強力な方法があるかどうか疑問に思います。

which apt >/dev/null 2>&1
if [ $? -eq 0 ]
then
    echo "apt"
fi
# etc...

答え1

バイナリではなくディストリビューションを識別することから始める必要があります。

以下は、bashスクリプトで動作する数行のコードです。

declare -A osInfo;
osInfo[/etc/redhat-release]=yum
osInfo[/etc/arch-release]=pacman
osInfo[/etc/gentoo-release]=emerge
osInfo[/etc/SuSE-release]=zypp
osInfo[/etc/debian_version]=apt-get
osInfo[/etc/alpine-release]=apk

for f in ${!osInfo[@]}
do
    if [[ -f $f ]];then
        echo Package manager: ${osInfo[$f]}
    fi
done

これらのファイルが変更されたため、この方法は失敗する可能性がありますが、これは非常に非標準の構成であるため、ほとんどの場合機能します。

答え2

次の質問に対する許可された回答から始めてください。単純なシェルスクリプトから展開名とバージョン番号をどのように取得できますか?。次に、検出されたディストリビューションに従って、使用するパッケージマネージャを決定します。

答え3

別のルートを確認した後、このルートを選択しました。これは、多くのDockerコンテナを実行しており、curl / jqが必要で、ジョブ間で利用可能なアイテムに依存できない場合に発生します。

script:
 - packagesNeeded='curl jq'
 - if [ -x "$(command -v apk)" ];       then sudo apk add --no-cache $packagesNeeded
 - elif [ -x "$(command -v apt-get)" ]; then sudo apt-get install $packagesNeeded
 - elif [ -x "$(command -v dnf)" ];     then sudo dnf install $packagesNeeded
 - elif [ -x "$(command -v zypper)" ];  then sudo zypper install $packagesNeeded
 - else echo "FAILED TO INSTALL PACKAGE: Package manager not found. You must manually install: $packagesNeeded">&2; fi

純粋なbashでは:

packagesNeeded=(curl jq)
if [ -x "$(command -v apk)" ];
then
    sudo apk add --no-cache "${packagesNeeded[@]}"
elif [ -x "$(command -v apt-get)" ];
then
    sudo apt-get install "${packagesNeeded[@]}"
elif [ -x "$(command -v dnf)" ];
then
    sudo dnf install "${packagesNeeded[@]}"
elif [ -x "$(command -v zypper)" ];
then
    sudo zypper install "${packagesNeeded[@]}"
else
    echo "FAILED TO INSTALL PACKAGE: Package manager not found. You must manually install: "${packagesNeeded[@]}"">&2;
fi

command -v終了ステータスを直接テストすることもできます。

if command -v apk &> /dev/null
then
    sudo apk add ...
fi

答え4

私はここでいくつかのアイデアを借りて、リリースのために他の場所でもいくつかのアイデアを借りました。私はこれをコンテナイメージビルドの一部として使用します。まず、基本イメージの展開を知らずに「汎用」インストールを行います。もちろん、パッケージ名がディストリビューションによって異なる場合、パッケージ名はそのまま失敗します。

#!/bin/bash
pkg_install () {

local distro;local cmd;local usesudo
declare -A pkgmgr
pkgmgr=( \
[arch]="pacman -S --noconfirm" \
[alpine]="apk add --no-cache" \
[debian]="apt-get install -y" \
[ubuntu]="apt-get install -y" \
)

distro=$(cat /etc/os-release | tr [:upper:] [:lower:] | grep -Poi '(debian|ubuntu|red hat|centos|arch|alpine)' | uniq)
cmd="${pkgmgr[$distro]}"
[[ ! $cmd ]] && return 1
if [[ $1 ]]; then
[[ ! $EUID -eq 0 ]] && usesudo=sudo 
echo installing packages command: $usesudo $cmd $@
$usesudo $cmd $@
else 
echo $cmd
fi
}

# if script was executed then call the function
(return 0 2>/dev/null) || pkg_install "$@"

直接実行またはインポートして関数を呼び出すことができます。私はcentosやredhatを使用しませんが、その項目を配列に追加したり、サポートしていない項目を削除したりできます。

私はposixバージョンを書かなければならなかったので(alpineのようないくつかの基本イメージにはデフォルトでbashがインストールされていないので)ここにあります。

#!/bin/sh
hm_hash() {
    echo "$1" | md5sum -
}

hm_put() {
    echo "$3" > "$1/$(hm_hash "$2")"
}

hm_get() {
    cat "$1/$(hm_hash "$2")"
}

pkg_install () {

local distro;local cmd;local usesudo; local pkgmgr
pkgmgr="$(mktemp -d)"
hm_put "$pkgmgr" arch "pacman -S --noconfirm" 
hm_put "$pkgmgr" alpine "apk add --no-cache"
hm_put "$pkgmgr" debian "apt-get install -y"
hm_put "$pkgmgr" ubuntu "apt-get install -y" 

distro=$(cat /etc/os-release | tr [:upper:] [:lower:] | grep -Poi '(debian|ubuntu|red hat|centos|arch|alpine)' | uniq)
cmd=$(hm_get "$pkgmgr" $distro 2> /dev/null)
rm -rf $pkgmgr
if [ ! -z "$cmd" ]; then
    if [ -z "$1" ]; then
    echo $cmd
    else 
    echo installing packages command: $cmd $@
    $cmd $@
    fi
 else  
   return 1  
 fi  
}

# if script was executed then call the function
(return 0 2>/dev/null) || pkg_install "$@"

関連情報