为什么awk中的split(string,regex)使用第一个位置的最后一个字段?

时间:2014-11-26 22:19:09

标签: bash awk

快速awkscript如下:

awk ' BEGIN{
split("A\nB\nC\nD", fooarray)
i=0
for (i in fooarray) print fooarray[i] 
} '

输出:

D
A
B
C

我觉得我错过了一些重要的细节,但是D在最后的位置怎么样?如在

A
B
C
D

2 个答案:

答案 0 :(得分:1)

awk不保证在使用in时您将遍历数组的顺序。

如果您想确保订单,您可以手动遍历数组(使用split)的返回值以数字方式行走。

或者,对于awk 4+的版本(我相信),您可以将PROCINFO["sorted_in"]设置为适当的值。有关详细信息,请参阅GNU Awk User’s Guide

答案 1 :(得分:1)

D IS位于最后一个位置,您只是不按其索引的连续数字顺序访问数组。看:

awk 'BEGIN{
split("A\nB\nC\nD", fooarray)
for (i in fooarray) print fooarray[i]
print "-------"
for (i=1; i in fooarray; i++) print fooarray[i]
}'
D
A
B
C
-------
A
B
C
D

我觉得这个话题引起了很多混乱,所以让我们看看我是否可以澄清它:

awk数组的两个基本特性是:

  1. 所有数组索引都是字符串,即使是看起来很数字的字符串,
  2. 数组存储为哈希表以提高效率。
  3. 因此,假设您有一个像"A B C"这样的字符串要调用split()来存储在数组中。当你做split("A B C", arr)时,你会在记忆中得到这样的东西:

     arr[  "3:C"   "1:A"    "2:B"   ]
    

    即。值A,B和C被散列到一些存储器位置并存储在那里以及索引的值,该索引指示它们在原始字符串中出现的顺序。散列算法可以按任何顺序将它们放入内存中。 Google"哈希表"。所以数组实际上存储为这个哈希表:

    arr content @ address 1 = "index=3, value=C"
    arr content @ address 2 = "index=1, value=A"
    arr content @ address 3 = "index=2, value=B"
    

    效率的in运算符(否则为什么要使用哈希表)只是按照它们存储在内存中的顺序访问数组的元素,所以当你这样做时

    for (i in arr)
    

    您将按照它们存储在哈希表中的顺序获取arr的内容:

    address=1 => i = 3, arr[i] = C
    ++address => i = 1, arr[i] = A
    ++address => i = 2, arr[i] = B
    

    i设置为3然后设置为1然后设置为2,因此arr [i]的值为C,然后是A,然后是B.请注意简单有效的算术++address来遍历{{}的内容1}}。

    如果另一方面你写道:

    arr

    然后awk将for (i=1; i in arr; i++) 设置为i然后必须对数组进行哈希查找以搜索具有索引1的元素并打印出来以便得到:< / p>

    1

    看到效率的差异?现在我们不再简单地逐步遍历内存地址,我们正在为每个所需的索引进行哈希查找。

    在条件上下文中编写i=1 search arr for address containing index i=1 => address = 2, i = 1, arr[1] = A ++i search arr for address containing index i=2 => address = 3, i = 2, arr[2] = B ++i search arr for address containing index i=3 => address = 1, i = 3, arr[3] = C 时,例如i in arrif (i in arr)而不是循环范围上下文for (i=1; i in arr; i++)那么你要求awk做的就是for (i in arr)的哈希查找,看它是否存在于数组中:< / p>

    i

    如果您有一个使用字符串索引手动填充的数组,如:

    search arr for address containing index i
    return 1 if found, 0 otherwise.
    

    并假设散列算法根据其值的长度创建数组内容然后你得到:

    arr["First"] = "Bill"
    arr["Last"]  = "Smith"
    arr["Title"] = "Mr."
    

    并且上面描述的所有内容都将以完全相同的方式工作,因此第一个示例使用数字化索引1,2和3的事实与awk中的数组工作方式完全无关 - 所有索引都是字符串并且数组内容存储为arr[ "Title:Mr." "First:Bill" "Last:Smith" ] 对的哈希表。

    在GNU awk中,您可以更改index + value运算符的行为,以便根据各种条件查找数组内容,而不是通过填充in来简单地遍历地址 - 您可以将其设置为示例到特定的预定义字符串,告诉PROCINFO["sorted_in"]根据索引的数字或字符串顺序,升序或降序或各种其他标准查找数组内容,您可以编写自己的函数来控制顺序。如果您需要特定的数组遍历顺序,这对于改善代码的简洁性非常有用,但如果您使用它并且不需要它,则显然会带来性能损失。有关详细信息,请参阅http://www.gnu.org/software/gawk/manual/gawk.html#Controlling-Array-Traversal

    希望这有助于解释awk数组存储和in运算符的工作方式。如果没有 - 抱歉引起混乱!