ubuntu 间接引用bash中的散列表

mbjcgjjk  于 2022-11-02  发布在  其他
关注(0)|答案(2)|浏览(283)

我正在写一个脚本来从.deb文件安装软件包,但首先,我想检查每个软件包是否已经安装。我有一个config文件,其中包含了软件包的信息,如hashmap,如下所示:

  1. declare -A package_a=(
  2. [name]="utility-blah"
  3. [ver]="1.2"
  4. [arch]="amd64"
  5. )
  6. declare -A package_b=(
  7. [name]="tool-bleh"
  8. [ver]="3.4"
  9. [arch]="all"
  10. )
  11. # and so on and so forth

我的安装脚本提供了配置文件,我希望它遍历软件包,检查它们是否已安装,如果未安装,则安装它们,如下所示:

  1. source packages.config
  2. declare -a packageList=("package_a" "package_b" "package_d")
  3. for package in ${packageList[@]}; do
  4. # Check if the specific version is installed already
  5. if apt show ${package[name]}=${package[ver]}; then
  6. echo ${package[name]} ${package[ver]} is already installed.
  7. else
  8. echo Installing ${package[name]}
  9. sudo apt install path/to/files/${package[name]}_${package[ver]}_${package[arch]}.deb
  10. fi
  11. done

如何让package指向包含包信息的散列表,并在下面的命令中使用它?
我在Ubuntu 18.04上使用Bash 4.4.20

kpbwa7wx

kpbwa7wx1#

使用nameref的一个想法是:

  1. source packages.config
  2. declare -a packageList=("package_a" "package_b" "package_d")
  3. for pkg in "${packageList[@]}"; do # change variable name
  4. declare -n package="${pkg}" # declare nameref; rest of code remains the same ...
  5. # Check if the specific version is installed already
  6. if apt show ${package[name]}=${package[ver]}; then
  7. echo ${package[name]} ${package[ver]} is already installed.
  8. else
  9. echo Installing ${package[name]}
  10. sudo apt install path/to/files/${package[name]}_${package[ver]}_${package[arch]}.deb
  11. fi
  12. done

或者(正如M. Nejat艾丹和Benjamin W.所指出的)declare -n可以在while循环之前进行,例如:

  1. declare -n package
  2. for package in "${packageList[@]}"; do
  3. # Check if the specific version is installed already
  4. if apt show ${package[name]}=${package[ver]}; then
  5. echo ${package[name]} ${package[ver]} is already installed.
  6. else
  7. echo Installing ${package[name]}
  8. sudo apt install path/to/files/${package[name]}_${package[ver]}_${package[arch]}.deb
  9. fi
  10. done

简单测试:

  1. declare -n package
  2. for package in ${packageList[@]}; do
  3. echo "${!package} : ${package[name]}"
  4. done

这将生成:

  1. package_a : utility-blah
  2. package_b : tool-bleh
  3. package_d :
展开查看全部
zdwk9cvp

zdwk9cvp2#

这种类型的输入数据更适合JSON,而不是使用bash关联数组和间接寻址。
假设您有一个packages.json

  1. {
  2. "packages": [
  3. {
  4. "package": "package_a",
  5. "name": "utility-blah",
  6. "ver": "1.2",
  7. "arch": "amd64"
  8. },
  9. {
  10. "package": "package_b",
  11. "name": "utility-bleh",
  12. "ver": "3.4",
  13. "arch": "all"
  14. },
  15. {
  16. "package": "apache2",
  17. "name": "Apache2 http server",
  18. "ver": "2.4.52-1ubuntu4.1",
  19. "arch": "all"
  20. }
  21. ]
  22. }

这样简单的POSIX shell脚本能够根据需要处理它:

  1. # ! /bin/sh
  2. # Fields are tab-delimited, records end with newline
  3. IFS=$(printf '\t')
  4. # Parses json input into record lines
  5. jq -r '.packages[]|(.package + "\t" + .name + "\t" + .ver)' packages.json |
  6. # Iterates records, reading fields
  7. while read -r package name ver; do
  8. {
  9. # Query package for installed status and version
  10. # formatted into two fields
  11. dpkg-query -W --showformat='${db:Status-Abbrev}\t${Version}' "${package}" || :
  12. } 2>/dev/null | {
  13. # Reads status and installed version
  14. read -r status installed_ver _
  15. # If status is installed 'ii ' and installed version matches'
  16. if [ "${status}x" = 'ii x' ] && [ "${ver}x" = "${installed_ver}x" ]; then
  17. printf '%s %s is already installed.\n' "${name}" "${ver}"
  18. else
  19. printf 'Installing %s.\n' "${name}"
  20. fi
  21. }
  22. done

输出示例:

  1. nstalling utility-blah.
  2. nstalling utility-bleh.
  3. Apache2 http server 2.4.52-1ubuntu4.1 is already installed.
展开查看全部

相关问题