bash, пара ключ-значение для определения используемого менеджера пакетов

#bash #dictionary #key-value #package-managers

Вопрос:

Я хочу обнаружить диспетчер пакетов в системе, а затем использовать его позже в своем сценарии. Однако я чувствую, что это неуклюже.

 type apt    amp;> /dev/null amp;amp; MANAGER=apt    amp;amp; DISTRO="Debian/Ubuntu"
type yum    amp;> /dev/null amp;amp; MANAGER=yum    amp;amp; DISTRO="RHEL/Fedora/CentOS"
type dnf    amp;> /dev/null amp;amp; MANAGER=dnf    amp;amp; DISTRO="RHEL/Fedora/CentOS"   # $MANAGER=dnf will be default if both dnf and yum are present
type zypper amp;> /dev/null amp;amp; MANAGER=zypper amp;amp; DISTRO="SLES"
type apk    amp;> /dev/null amp;amp; MANAGER=apk    amp;amp; DISTRO="Alpine"
 

Что я хотел бы сделать, так это определить какой-то массив или пару ключ-значение, чтобы

 apt, Debian/Ubuntu
dnf, RedHat/Fedora/CentOS
 

а затем есть функция, которая выделяет на основе этого псевдокода:

 for each item in the key-value pair {
    type {key} amp;> /dev/null amp;amp; MANAGER={key} amp;amp; DISTRO={value}
}
 

Может кто-нибудь показать мне, как это можно построить в баше?

Комментарии:

1. Ansible, например, уже абстрагирует конкретный используемый менеджер пакетов.

2. Есть ли у вас причина хотеть сделать его «менее неуклюжим»? Накладные расходы? Я бы действительно построил его таким, какой ты есть, если бы сделал это сам. Я вижу «более чистый код» .. Но ничего такого, что могло бы повлиять на то, как работает программа … И эта длинная рука, на мой взгляд, делает скрипт более понятным для отладки.

Ответ №1:

Просто определите текст. Столбцов, разделенных пробелами, с элементами, разделенными новой строкой.

 list=$(cat <<EOF
apt Debian/Ubuntu
dnf RedHat/Fedora/CentOS
EOF
)

while IFS=' ' read -r key value; do
   if type "$key"; then...
done <<<"$list"
 

Предпочитаю использовать if вместо amp;amp; для удобства чтения. Вы можете использовать другой разделитель, чтобы хранить пробелы в элементах, предварительно обработать список, если хотите оставить некоторые комментарии.

Вы также можете использовать несколько массивов:

 keys=(apt dnf)
managers=(Debian/Ubuntu RedHat/Fedora/CentOS)
for ((i=0;i<${#keys};  j)); do
    if type "${keys[i]}"; then
 

Вы также можете использовать ассоциативные массивы:

 declare -A managers=(
  [apt]=Debian/Ubuntu
  [dnf]=RedHat/Fedora/CentOS
)
for key in "${!managers[@]}"; do
   manager=${managers["$key"]}
done
 

Предпочитайте использовать переменные нижнего регистра в сценариях. Проверьте свои сценарии с помощью shellcheck.

Ответ №2:

Определение такого массива не будет значительно менее неуклюжим, чем то, что у вас уже есть.

 declare -A managers
managers[apt]="Debian/Ubuntu"
managers[yum]="RHEL/Fedora/CentOS"
# etc

for k in "${!managers[@]}"; do
    if type "$k"; then
        MANAGER=$k
        DISTRO=${managers[$k]}
        break
    fi
done