#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