识别系统包管理器

识别系统包管理器

有没有办法(从脚本)来识别默认的系统包管理器?

为了澄清,我想做的是运行给定的命令,在 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

从这个问题的公认答案开始:如何在简单的 shell 脚本中获取发行版名称和版本号?。然后,根据检测到的发行版决定要使用哪个包管理器。

答案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 "$@"

相关内容