【问题标题】:Bash associative array orderingBash 关联数组排序
【发布时间】:2017-05-04 23:26:52
【问题描述】:

如果我想在 bash 中分别传递关联数组的键和值,并使用类似

./foo.py -k "${!args[@]}" -v "${args[@]}"

它们会以相同的顺序出现吗?我真的不在乎其他 k=v 对存储在什么中,但我确实需要知道我是否可以指望键和值出现,这样键数组中的第 3 项实际上是值数组中的第三项。

我知道关联数组是“无序的”,并且无论您将它们添加到数组中的任何顺序都与它们的输出方式无关,但我想知道底层存储行为是否意味着它们将始终以相同的顺序输出.

【问题讨论】:

  • 不是答案,因为我必须审核代码才能提供答案。但是,如果不是这样,我会非常感到惊讶,如果只是因为产生不同的排序需要看似不必要的努力(只要数组在扩展之间没有被修改)。
  • @chepner:你不能得出这个结论。我不了解 bash,但在其他语言中,有些保持顺序,有些则不保持,具体取决于实现。在其他情况下,这甚至可能在版本之间发生变化。例如,Tcl - 直到(我认为)版本 8.5 - 保证订单被保留,但他们后来改变了它。
  • 您是否声称 Tcl 在每次访问时都会执行哈希随机化之类的操作?如果name 在两次调用之间根本没有修改,那么array get name 在每次调用时可以返回不同的列表?
  • 您可能应该选择一个答案。

标签: arrays bash shell associative-array


【解决方案1】:

数组不是解决这个问题的方法,尤其是关联数组。 即使它们确实以相同的顺序出现,您也将拥有多个密钥 单个 -k 选项,导致语法错误。数组还有a Bashism, 并且不是由 POSIX 定义的。更好的解决方案是这样的:

./foo.py -k key1,key2,key3 -v val1,val2,val3

那么 Python 肯定可以拆分输入字符串吗?我做了类似的事情 使用 POSIX 外壳:

tr , '\n' > keys <<eof
$1
eof
tr , '\n' > vals <<eof
$2
eof
paste -d '\n' keys values |
while
  read key
  read val
do
  printf 'key: %s, val: %s\n' "$key" "$val"
done

当然,使用 Python 会更容易,因为您可以将 字符串直接放入数组而不使用文件。

【讨论】:

  • 这其实是对数组的一种很好的利用;它们的缺席是 POSIX 规范中更明显的遗漏之一。
  • @chepner 我承认知道数组不是 POSIX 是一个打击——有点像知道不推荐使用同步 JavaScript
  • 相比之下,Python 中没有多行 lambda 是天堂。
【解决方案2】:

似乎答案是肯定的,键和值将始终保持相同的顺序,基于我在 Bash 版本 4.3 中找到的代码,assoc.c,可用here。数组的键和值分别由函数assoc_keys_to_word_listassoc_to_word_list 检索。这两个函数都委托给assoc_to_word_list_internal,它在两种情况下都运行相同的循环,并且仅根据t 参数(第482-503 行)区分要检索的项目的类型:

static WORD_LIST *
assoc_to_word_list_internal (h, t)
     HASH_TABLE *h;
     int t;
{
  WORD_LIST *list;
  int i;
  BUCKET_CONTENTS *tlist;
  char *w;

  if (h == 0 || assoc_empty (h))
    return((WORD_LIST *)NULL);
  list = (WORD_LIST *)NULL;

  for (i = 0; i < h->nbuckets; i++)
    for (tlist = hash_items (i, h); tlist; tlist = tlist->next)
      {
  w = (t == 0) ? (char *)tlist->data : (char *)tlist->key;
  list = make_word_list (make_bare_word(w), list);
      }
  return (REVERSE_LIST(list, WORD_LIST *));
}

如果您想知道,make_word_listarray.c/h 中定义。它只是将一个新的WORD_LIST 节点附加到现有的链表中。

虽然这并没有提供始终支持您期望的行为的合同保证,但它很好地表明您可以安全地使用您的调用约定,至少目前是这样。关联数组仅适用于 Bash 的事实使得该实现更像是一个有效的参考。

【讨论】:

    猜你喜欢
    • 2012-01-03
    • 2015-07-03
    • 1970-01-01
    • 2019-04-23
    • 1970-01-01
    • 2011-02-26
    • 2011-01-28
    • 1970-01-01
    相关资源
    最近更新 更多