有没有办法(从脚本)来识别默认的系统包管理器?
为了澄清,我想做的是运行给定的命令,在 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 "$@"