首页 > 解决方案 > 如何将终端输出块拆分为可以循环的数组元素

问题描述

只是寻找将多行输出拆分的最佳实践方法,例如您可能从命令或 curl 请求中获得使用 Bash 或 Zsh 的条目数组

例如,如果一个命令或打印一个文件给出了一个输出

"User A:
    Name: Bob
    Age: 36
User B: 
    Name: Jeff
    Age: 42"

你将如何创建一个数组,其中每个用户都是数组中的一个条目?

或者,如果您的输出设备类似于

"Computer A:
Name Bob's Computer
Serial 123456
Uptime 12hr
Computer B:
Name Jeff's Computer
Serial 789101
Uptime 8hr"

您将如何将其拆分为一组计算机,以便您可以执行诸如通过数组中的元素数量查看有多少台计算机,或者将它们逐个传递给另一个命令等事情?

我一直在寻找分割字符串和输出的方法,我找到的所有答案似乎都是针对用单个字符分隔符分割单行。我认为这样做的方法是在上述示例中使用“用户”或“计算机”作为分隔符进行拆分,或者将它们用作读取和读取的模式,但我不知道该怎么做在 Bash 中?

提前致谢

标签: bashzsh

解决方案


假设:

  • 您想将这些行拆分为例如“计算机 A”块和“计算机 B”块,然后将计算机(或用户)名称存储到一个数组中。
  • (可能是可选的)您想要解析诸如“名称”、“序列”之类的属性行......并将它们存储在数组数组中。

那么请您尝试以下方法:

#!/bin/bash

str="Computer A:
Name Bob's Computer
Serial 123456
Uptime 12hr
Computer B:
Name Jeff's Computer
Serial 789101
Uptime 8hr"

keyword="Computer"                      # the keyword to split the lines into array
declare -A hash                         # create associative array
i=0                                     # index of the "real" array name

readarray -t a <<< "$str"               # read the string splitting on newlines
for line in "${a[@]}"; do               # loop over lines
    if [[ $line =~ ^${keyword}[[:blank:]]+([^:]+): ]]; then
                                        # if the line starts with the "keyword"
        name="${BASH_REMATCH[1]}"       # name is assigned to "A" or "B" ...
        hash[$name]="array$i"           # define "real" array name and assign the hash value to it
        declare -A "array$i"            # create a new associative array with the name above
        declare -n ref="array$i"        # "ref" is a reference to the newly created associative array
        (( i++ ))                       # increment the index for new entry
    else
        read -r key val <<< "$line"     # split on the 1st blank character
        key=${key%:}                    # remove traiking ":"
        key=${key## }                   # remove leading whitespace(s)
        ref[$key]=$val                  # store the "key" and "val" pair
    fi
done

 print number of elements of the array
echo "The array has ${#hash[@]} elements"

# print the values of each array of the array
for i in "${!hash[@]}"; do              # loop over "A" and "B"
    echo "$i"                           # print it
    declare -n ref=${hash[$i]}          # assign ref to array name "array0" or "array1" ... then make it an indirect reference
    for j in "${!ref[@]}"; do           # loop over "${array0[@]}" or "${array1[@]}" ...
        echo "  $j => ${ref[$j]}"
    done
done

输出:

The array has 2 elements
A
  Name => Bob's Computer
  Uptime => 12hr
  Serial => 123456
B
  Name => Jeff's Computer
  Uptime => 8hr
  Serial => 789101

请注意bash,它本身不支持数组数组,我们需要使用declare -n语句来创建对变量的引用,这会降低代码的可读性。如果Python是您的选择,请告诉我。它将更适合此类任务。


推荐阅读