拆分文件并将其放入相应的数据结构中?


10

我有一个包含以下单行的文件:

{machineA=[0, 1024, 4, 1028], machineB=[1, 1025, 5, 1029]}

其中有两个数据集:

machineA=[0, 1024, 4, 1028]
machineB=[1, 1025, 5, 1029]

现在,我需要阅读上述文件并将其拆分,以便可以如上所述提取每台机器的信息并将其存储在某种数据结构中。

当前,我很困惑应该在bash shell脚本中使用哪种数据结构。如果我使用Java进行此操作,则可以使用,Map<String, Set<String>>但不确定在shell脚本中应该使用什么。

在将其存储在某种数据结构中之后,我需要对其进行迭代并打印出结果。

我可以使用以下shell脚本读取以上文件:

#!/bin/bash

while read -r line; do
       echo "$line"
    done < data.txt

但是我不确定如何以上述方式拆分上述行数据,以便能够提取每台机器的信息,然后将其存储在某些数据结构中?

更新:-

以下是我遵循glenn给出的建议后得到的shell脚本-

#!/bin/bash

while read -r line; do
       echo "$line"
       declare -A "$(
            echo "x=("
            grep -oP '(\w+)(?==)|(?<==\[).*?(?=\])' <<< "$line" |
              tr -d , |
              paste - - |
              sed 's/^/[/; s/\t/]="/; s/$/"/'
            echo ")"
        )"

        for key in "${!x[@]}"; do           # need quotes here
            for element in ${x[$key]}; do   # no quotes here
                printf "%s\t%s\n" "$key" "$element"
            done
        done    
    done < primary.txt

Answers:


4

bash数据结构对于2维数组来说都太基本了。您确定这是您要使用的工具吗?

使用bash和GNU grep,您可以进行以下令人讨厌的混乱:

line='{machineA=[0, 1024, 4, 1028], machineB=[1, 1025, 5, 1029]}'
declare -A "$(
    echo "x=("
    grep -oP '(\w+)(?==)|(?<==\[).*?(?=\])' <<< "$line" |
      tr -d , |
      paste - - |
      sed 's/^/[/; s/\t/]="/; s/$/"/'
    echo ")"
)"

for key in "${!x[@]}"; do           # need quotes here
    for element in ${x[$key]}; do   # no quotes here
        printf "%s\t%s\n" "$key" "$element"
    done
done
machineA    0
machineA    1024
machineA    4
machineA    1028
machineB    1
machineB    1025
machineB    5
machineB    1029

这非常脆弱。我会用Perl这样的东西:仍然很丑但更简洁

echo "$line" | perl -MData::Dumper -ne '
    s/=\[/=>[/g; 
    eval "\$x=$_";
    # do something with your data structure (a hash of arrays) 
    print Dumper($x)
'
$VAR1 = {
          'machineB' => [
                          1,
                          1025,
                          5,
                          1029
                        ],
          'machineA' => [
                          0,
                          1024,
                          4,
                          1028
                        ]
        };

感谢您的建议。我可能会使用shell脚本选项,因为最后我需要使用scp,所以我相信在shell脚本中执行scp会很容易。但是无论如何,让我们看看结果如何。在合并您的建议之后,我已经用实际的shell脚本更新了我的问题。请看一下,让我知道它看起来是否正确,是否有任何您想修改的内容,也请告诉我。
SSH

+1与eval那里的动作相当流畅。
Joseph R.

1

Shell文本处理实用程序主要用于处理用每行一个记录和由空格或固定字符分隔的字段表示的数据。这种格式完全不同,您将无法直接处理它。

一种方法是预处理文件以适合可以轻松处理的格式类型。我假定除了此处描绘的以外,不使用方括号和花括号(整个文本中的括号,机器值列表周围的方括号)。

<data.txt sed -e 's/^{//' -e 's/}$//' -e 's/ *= *\[/,/g' -e 's/, */,/g' -e 's/\] *$//' -e 's/] *, */\n/g'

结果每行有一台机器,逗号分隔记录。以下代码段解析了每行上的计算机名称,并在其中留下了逗号分隔的值列表values

 | while IFS=, read -r machine values; do 

以下特定于bash的代码段将值放入数组中。

 | while IFS=, read -r -a values; do
  machine=${values[0]}; shift values
  echo "There are ${#values[@]} on machine $machine"
done

@吉尔斯:谢谢你的建议。是否还可以获得每台计算机的文件总数?使用上面相同的命令表示总计数?像上面的例子一样,machineA有四个文件,machineB也有四个文件
SSH


0

您可以awk用来完成任务。

awk -F "], " '/[a-zA-Z]=\[[0-9]/ {gsub(/{|}/,""); for(i=1; i<=NF; i++) if($i !~ /\]$/) print $i"]"; else print $i}' data.txt

machineA=[0, 1024, 4, 1028]
machineB=[1, 1025, 5, 1029]

谢谢约翰。是否可以获得每台计算机的文件总数。像上面的示例一样,machineA具有四个文件,而MachineB也具有四个文件。是否有可能做到这一点?
SSH

0

看起来有点像JSON。您可以将其修复为正确的JSON并使用JSON工具:

$ echo '{machineA=[0, 1024, 4, 1028], machineB=[1, 1025, 5, 1029]}' |  perl -pe 's!\b!"!g; s/=/:/g' | json_pp
{
   "machineB" : [
      "1",
      "1025",
      "5",
      "1029"
   ],
   "machineA" : [
      "0",
      "1024",
      "4",
      "1028"
   ]
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.