기본 시스템 패키지 관리자를 식별하는 방법(스크립트에서)이 있습니까?
명확히 하자면, 제가 하고 싶은 것은 주어진 명령을 실행하는 것입니다. 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 컨테이너를 실행 중이고 컬/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 "$@"