【问题标题】:Bash: How do I add an element to an array that is stored in a variable? [closed]Bash:如何将元素添加到存储在变量中的数组中? [关闭]
【发布时间】:2021-01-20 21:57:08
【问题描述】:

TL;DR

我在 bash 中有两个数组变量,archPkgsnpmPkgs。稍后在我的代码中,我有一个变量变量pkgPlatform,它可以指向其中任何一个。我想通过这个变量变量向数组中添加一个元素。如何在 bash 中做到这一点?

详情

我正在尝试用 Python 和 Bash 编写一个安装后脚本,并且我正在编写一个安装所有需要的包的 bast 脚本。下面是它的代码。

# List of all Arch packages
archPkgs=(
        # Display server
        'xorg'

        # Display manager
        'lightdm'
        'lightdm-webkit2-greeter'
        'lightdm-webkit-theme-litarvan'

        # Editor
        'neovim-nightly-bin'

        # WM
        'i3-gaps'
        'i3lock'
        'i3status'
        'picom'
        'rofi'

        # Syncing
        'syncthing'

        # Printing
        'cups'

        # Networking
        'network-manager-applet'
        'avahi'
        'nss-mdns'
        'reflector'

        # Browsing
        'firefox'
        'firefox-nightly'

        # Terminals, shell, programming, and other programsn and utilities
        'kitty'
        'bash-completion'
        'nodejs'
        'npm'
        'python'
        'python-pip'

        # Notifications
        'dunst'

        # Gaming
        'steam'

        # Media
        'vlc'
        'playerctl'
        'spotify'

        # Audio
        'pasystray'
        'pulseaudio'
        'pulseaudio-alsa'
        'pulseaudio-bluetooth'
        'pavucontrol'
        'lib32-libpulse'
        'lib32-alsa-plugins'
        'alsa-utils'
        'alsa-firmware'

        # Fonts
        'noto-fonts-cjk'
        'noto-fonts-emoji'
        'ttf-iosevka'
        'ttf-liberation'
        'ttf-opensans'

        # Drive tools + backups
        'udiskie'
        'borg'

        # Power management
        'xfce4-power-manager'

        # Themes
        'arc-gtk-theme'
        'breeze'

        # Screenshots
        'flameshot'

        # Bluetooth
        'blueman'
        'bluez'
        'bluez-utils'
)

npmPkgs=(
    # Language servers
    'vim-language-server'
    'bash-language-server'

    # Type checkers
    'pyright'
)


while true; do
    echo Are there any packages you would like to manage? Enter [arch/npm] [add/remove][ name of package].
    read pkgPlatform pkgAction pkgName

    if [ "$pkgPlatform" == 'arch' ]; then
        pkgPlatform=archPkgs
    elif [ "$pkgPlatform" == 'npm' ]; then
        pkgPlatform=npmPkgs

    elif [ "$pkgPlatform" == 'quit' ] || [ "$pkgAction" == 'quit' ] || [ "$pkgAction" == 'quit' ]; then
        echo Continuing...
        break

    else
        echo "Unknown option."
        continue
    fi

    if [ "$pkgPlatform" != 'quit' ] && [ "$pkgAction" != 'quit' ] && [ "$pkgName" != 'quit' ]; then
        while true; do
            if [ "$pkgAction" == 'add' ]; then
                $pkgPlatform+=pkgName
                break

            elif [ "$pkgAction" == 'remove' ]; then
                unset "$pkgName"[$pkgPlatform]
                break

每当我运行它时,都会发生这种情况。

[johnny@lj-laptop post_install_scripts]$ ./02_pkgs.sh 
Packages to be installed:

Arch Packages
xorg lightdm lightdm-webkit2-greeter lightdm-webkit-theme-litarvan neovim-nightly-bin i3-gaps i3lock i3status picom rofi syncthing cups network-manager-applet avahi nss-mdns reflector firefox firefox-nightly kitty bash-completion nodejs npm python python-pip dunst steam vlc playerctl spotify pasystray pulseaudio pulseaudio-alsa pulseaudio-bluetooth pavucontrol lib32-libpulse lib32-alsa-plugins alsa-utils alsa-firmware noto-fonts-cjk noto-fonts-emoji ttf-iosevka ttf-liberation ttf-opensans udiskie borg xfce4-power-manager arc-gtk-theme breeze flameshot blueman bluez bluez-utils

npm Packages
vim-language-server bash-language-server pyright
Are there any packages you would like to manage? Enter [arch/npm] [add/remove] [name of package].
When you are satisfied, enter "quit" instead of "add" or "remove".
npm add test
./02_pkgs.sh: line 153: npmPkgs+=pkgName: command not found
Packages to be installed:

Arch Packages
xorg lightdm lightdm-webkit2-greeter lightdm-webkit-theme-litarvan neovim-nightly-bin i3-gaps i3lock i3status picom rofi syncthing cups network-manager-applet avahi nss-mdns reflector firefox firefox-nightly kitty bash-completion nodejs npm python python-pip dunst steam vlc playerctl spotify pasystray pulseaudio pulseaudio-alsa pulseaudio-bluetooth pavucontrol lib32-libpulse lib32-alsa-plugins alsa-utils alsa-firmware noto-fonts-cjk noto-fonts-emoji ttf-iosevka ttf-liberation ttf-opensans udiskie borg xfce4-power-manager arc-gtk-theme breeze flameshot blueman bluez bluez-utils

npm Packages
vim-language-server bash-language-server pyright
Are there any packages you would like to manage? Enter [arch/npm] [add/remove] [name of package].
When you are satisfied, enter "quit" instead of "add" or "remove".

问题似乎在第 153 行。

目前我不太确定我的选择是什么。我粘贴了脚本,其中所有更改系统的行都被注释掉了,但是在运行它之前你还是应该看看它。

显然剧本还没有完成,我打算早点重新安排很多东西。

【问题讨论】:

  • 这将是一个更好的问题,您将其简化为仅显示问题的最小示例,而不是给我们您的整个脚本并让我们弄清楚。
  • 不过,在 bash 中,您可以使用 declare -a array_var 声明和排列数组。谷歌“bash 数组变量”,你会发现很多页面回答了你的问题。如果您无法弄清楚,请通过最小的示例提出有针对性的问题。
  • @joanis 好吧,我把脚本删减了一点。我也尝试了该变量,但它仍然无法正常工作。我将脚本顶部的数组更改为declare -a arrayname()
  • 您使用的+= 语法不适用于数组。我推荐的 Google 搜索给了我这个页面:opensource.com/article/18/5/… 在其中查找“填充数组”。
  • ShellCheck 有一些提示,例如Line 125: $pkgPlatform+=pkgName SC2281: Don't use $ on the left side of assignments.

标签: python node.js bash git npm


【解决方案1】:

改变

    if [ "$pkgPlatform" == 'arch' ]; then
        pkgPlatform=archPkgs
    elif [ "$pkgPlatform" == 'npm' ]; then
        pkgPlatform=npmPkgs

    if [ "$pkgPlatform" == 'arch' ] || [ "$pkgPlatform" == 'npm' ]; then
        declare -n platformPkgs="${pkgPlatform}Pkgs"

这使得 platformPkgs 成为所需数组的 nameref。然后您可以像使用普通数组变量一样使用platformPkgs

然后改变

            if [ "$pkgAction" == 'add' ]; then
                $pkgPlatform+=pkgName
                break

            elif [ "$pkgAction" == 'remove' ]; then
                unset "$pkgName"[$pkgPlatform]
                break

            if [ "$pkgAction" == 'add' ]; then
                platformPkgs+=( "$pkgName" )
                break

            elif [ "$pkgAction" == 'remove' ]; then
                ## not this => unset "platformPkgs[$pkgName]"
                # first, iterate through the array to find
                # the index for this value $pkgName,
                # then, unset "platformPkgs[$index]"
                # or rewrite the array except for the element at that index: 
                #   platformPkgs=( "${platformPkgs[@]:0:index}" "${platformPkgs[@]:index+1}" )
                break

【讨论】:

  • 这一行的意义何在,最后的Pkgs是做什么的?
  • 好吧,它似乎工作。感谢那。我确实注意到它不会像预期的那样删除条目。我可以将vim 添加到列表中并运行命令将其删除,它会删除列表中的第一个条目。这可能是什么原因造成的?
  • 哦,对,这些是数字索引数组,所以 $pkgName 中的字符串被强制为零(通过算术扩展,我不会在这里讨论)。由于要删除数组元素之一,因此必须遍历数组以找到与该元素匹配的索引,然后取消设置该数组索引。
【解决方案2】:

想要第 153 行执行的是

npmPkgs+=($pkgName)

但是您的目标变量已包含在变量本身中。请记住,shell 的初衷是构建命令行,变量替换仅在您使用 $ 运算符指向 shell 的情况下进行。

这样做的蛮力方法是

eval $pkgPlatform'+=($pkgname)'

它会替换您的目标名称,然后重新扫描结果行。

作为一个不相关的说明,您可以使用一些案例语句来清理该脚本很多

【讨论】:

    【解决方案3】:

    您遇到的错误是因为您没有正确地将项目附加到数组中,

    $pkgPlatform+=pkgName ##that way the bash script can't get what you mean
    

    所以,当你在变量pkgPlatform中添加一个项目时,可以这样做:

    pkgPlatform+=("$pkgName")
    

    【讨论】:

    • 这是不正确的:变量扩展不在=的左侧
    • 错误不是扩展,而是在左侧使用$。我将编辑我的答案。
    • $ 使其成为扩展:gnu.org/software/bash/manual/…
    猜你喜欢
    • 2012-10-12
    • 1970-01-01
    • 2020-04-29
    • 1970-01-01
    • 1970-01-01
    • 2012-10-17
    • 2014-05-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多