awk:将输出传递给关联数组

awk: passing output to associative array

是否可以将 awk 输出传递给关联数组?

例如,我有一个 test.csv 文件:

bill|gates|123
steve|jobs|234
elon|musk|345

如果我这样做:

awk 'BEGIN {FS="|"} {print ,,}' test.csv

我得到:

bill gates 123
steve jobs 234
elon musk 345

我能否在关联数组 (zsh) 中获取结果而不是此输出,如下所示?

typeset -A foo=(
  [bill gates]=123
  [steve jobs]=234
  [elon musk]=345
)

您可以使用此 awk 生成此输出,然后您可以 evalzsh 中使用此输出来创建您的关联数组:

awk -F '|' 'BEGIN {print "typeset -A foo=("}
{print "   [" ,  "]=" } END {print ")"}' file.csv

typeset -A foo=(
   [bill gates]=123
   [steve jobs]=234
   [elon musk]=345
)

您能否解析 awk 中的数据并将 shell 的 (awk) 结果 re-parsed 存储在数组中?当然可以,但是为什么不减少开销而让 shell 直接解析文件并存储在数组中呢?

declare -A foo=()

while IFS='|' read -r fname lname val
do
    ndx="${fname} ${lname}"
    foo[${ndx}]="${val}"
done < test.csv

这会生成:

$ typeset -p foo
typeset -A foo=( ['bill gates']=123 ['elon musk']=345 ['steve jobs']=234 )

一种可能:

typeset -a lines=("${(f)$(awk 'BEGIN {FS="|"} {print ,,}' test.csv)}")
typeset -a keys=("${(@)lines% *}")
typeset -a vals=("${(@)lines##* }")
typeset -A ary=(${keys:^vals})

部分作品:

  • ${(f)...} - 在换行符处拆分 awk 的输出。
  • ${...% *} - 删除从最后一个 space 到最后的所有内容,留下前两个字段作为密钥。对于 (@) 和 double-quotes,这将应用于 lines 数组中的每个元素。
  • ${...##* } - 删除直到最后一个 space 的所有内容,保留值。
  • ${...:^...} - 将两个数组压缩在一起,所以我们最终得到 key1 val1 key2 val2 ....
  • typeset -A ... - 使用 k1 v1 k2 v2 ... 语法创建关联数组。

另一个版本,仅使用zsh:

typeset -a lines=("${(f)$(<test.csv)}")
typeset -a keys=("${(@)"${(@)lines%|*}"//|/ }")
typeset -a vals=("${(@)lines##*|}")
typeset -A ary=(${keys:^vals})

此变体和下面的变体可以处理值中的 spaces,例如.csv 文件中的 j k|rowling|44 192 411 将创建元素 ['j k rowling']='44 192 411'.


通过对 awk 脚本进行一些更改,可以在一行中完成:

typeset -A ary=("${(@s:|:)${(f)"$(awk -F'|' '{print ,"|"}' test.csv)"}}")