【问题标题】:Associative Array with List of Files as Values …以文件列表为值的关联数组…
【发布时间】:2021-04-13 09:20:05
【问题描述】:

我在使用 Bash 的关联数组时遇到了一些问题:我正在寻找一种解决方案,将带有文件名的数组分配给关联数组。

它应该看起来像:

/Applications/Setup.app => ([0] = "/Applications/Setup.app/IDStore@2x.png"
                            [1] = "/Applications/Setup.app/IDMessages@2x.png"
                            [2] = "/Applications/Setup.app/IDMusic New@2x.png")

声明字典/哈希表/关联数组不是问题:

declare -A Dictionary

要获取我使用“readarray”的键,结合“find”:

readarray -d '' Applications < <(find "/Applications" -name "*.app" -print0)

如果目录的名称中有空格,则不是问题。现在我需要在应用程序的目录中找到 PNG 文件:

if [ ${#Applications[*]} -gt 0 ]; then
    for App in "${Applications[@]}"; do
        readarray -d '' Files < <(find "$App" -iname "*.png" -type f -print0)

        for File in "${Files[@]}"; do
            Dictionary["$App"]+="$File"
        done
    done
fi

我不明白的问题是,如何将第二个“查找”的结果作为文件列表添加到声明的关联数组中?如果我使用 Delimiter ' ' 设置 readarray 一些包含空格的文件被破坏。

下一个问题是如何获取 for-Loop 中的值?我也尝试过使用 readarray,但这不适用于名称中包含空格的文件。

for Key in "${!Dictionary[@]}"; do
    readarray -d ' ' Values <<< "${Dictionary[$Key]}"

    for Value in "${Values[@]}"; do
        echo "$Value"
    done
done

如果我运行上面的脚本,这就是我得到的:

/Applications/Setup.app/IDStore@2x.png/Applications/Setup.app/IDMessages@2x.png/Applications/Setup.app/IDMusic 
New@2x.png

但我想要这个:

/Applications/Setup.app/IDStore@2x.png
/Applications/Setup.app/IDMessages@2x.png
/Applications/Setup.app/IDMusic New@2x.png

是否有机会使用 Bash 5.0.3 进行这项工作?

目标是在没有 awk / grep / sed 的情况下使用大部分功能,因此它使用 Bash 的内置命令运行。

【问题讨论】:

  • 我唯一的想法是使用像jq这样的工具以像JSON这样的格式存储列表。但实际上,如果您需要二维数组,则首先不应该使用bash。使用具有真实数据结构的编程语言。

标签: arrays bash dictionary hashtable associative-array


【解决方案1】:

使用文件名填充数组时,请考虑使用任何文件名中都不存在的字符(作为分隔符)。 [注意:按照目前的编码,没有分隔符,因此文件名作为一条长线挤在一起]。

例如,假设文件名不包含换行符 (\n),并假设 find 返回以下内容:

/Applications/Setup.app/IDStore@2x.png
/Applications/Setup.app/IDMessages@2x.png
/Applications/Setup.app/IDMusic New@2x.png

我们可以像这样填充数组:

unset      Dictionary
declare -A Dictionary

App="/Applications/Setup.app"

# for sake of example, simulate find results by processing a list of files

for file in "/Applications/Setup.app/IDStore@2x.png" "/Applications/Setup.app/IDMessages@2x.png" "/Applications/Setup.app/IDMusic New@2x.png"
do
    Dictionary[${App}]+=$'\n'"${file}"     # use '\n' as delimiter
done

while IFS=$'\n' read -r line
do
    [[ -n "${line}" ]] &&                  # skip the initial '\n'
    printf "|%s|\n" "${line}"
done <<< "${Dictionary[@]}"

注意:管道添加到printf 格式作为视觉分隔符

这会生成:

|/Applications/Setup.app/IDStore@2x.png|
|/Applications/Setup.app/IDMessages@2x.png|
|/Applications/Setup.app/IDMusic New@2x.png|

【讨论】:

    【解决方案2】:

    数组数组,考虑这种方法:

    [[ ${Applications[@]} ]] && {
        for i in "${!Applications[@]}"; do
            readarray -d '' "Files$i" < <(find "${Applications[$i]}" -iname "*.png" -type f -print0)
            Dictionary["${Applications[$i]}"]="Files$i"
        done
    }
    

    然后使用这个来检索值:

    for key in "${!Dictionary[@]}"; do
        val="${Dictionary[$key]}[@]"
        echo "$key: ${!val}"
    done
    

    然后检查here

    【讨论】:

      【解决方案3】:

      只需修改伊万的好答案,怎么样:

      declare -A Dictionary
      readarray -d '' Applications < <(find "/Applications" -name "*.app" -print0)
      
      for i in "${!Applications[@]}"; do
          readarray -d '' "Files$i" < <(find "${Applications[$i]}" -iname "*.png" -type f -print0)
          Dictionary["${Applications[$i]}"]="Files$i"
      done
      
      for key in "${!Dictionary[@]}"; do
          echo "$key => "
          declare -n ary="${Dictionary[$key]}"
          for j in "${!ary[@]}"; do
              echo "  [$j] = ${ary[j]}"
          done
      done
      

      例如,如果我们有一个目录树如下:

      /Applications/
      ├── Bar.app
      │   ├── bar1.png
      │   └── bar2.png
      ├── Foo.app
      │   ├── foo1.png
      │   └── foo2.png
      └── Setup.app
          ├── IDMessages@2x.png
          ├── IDMusic New@2x.png
          └── IDStore@2x.png
      

      结果将是:

      /Applications/Foo.app => 
        [0] = Applications/Foo.app/foo1.png
        [1] = Applications/Foo.app/foo2.png
      /Applications/Bar.app => 
        [0] = Applications/Bar.app/bar1.png
        [1] = Applications/Bar.app/bar2.png
      /Applications/Setup.app => 
        [0] = Applications/Setup.app/IDStore@2x.png
        [1] = Applications/Setup.app/IDMusic New@2x.png
        [2] = Applications/Setup.app/IDMessages@2x.png
      

      【讨论】:

        猜你喜欢
        • 2017-02-26
        • 2020-04-04
        • 1970-01-01
        • 1970-01-01
        • 2013-12-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-04
        相关资源
        最近更新 更多