ファイルを分割して、対応するデータ構造に入れますか?


10

以下の1行を含むファイルがあります。

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

ここには2つのデータセットがあります。

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

ここで、上記のファイルを読み取り、上記のように各マシンの情報を抽出していくつかのデータ構造に格納できるように分割する必要があります。

現在、bashシェルスクリプトでどのデータ構造を使用すればよいか混乱しています。これをJavaで実行している場合は使用しますMap<String, Set<String>>が、シェルスクリプトで何を使用すればよいかわかりません。

そして、それを何らかのデータ構造に格納した後、それを反復して結果を出力する必要があります。

以下のシェルスクリプトを使用して上記のファイルを読み取ることができます。

#!/bin/bash

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

しかし、私は上記のラインデータをどのように分割して、各マシン情報を抽出し、それをいくつかのデータ構造に格納できるかわかりませんか?

更新:-

以下は、glennの提案に従って作成したシェルスクリプトです。

#!/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

回答:


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
                        ]
        };

提案をありがとう。最後にscpを使用する必要があるので、シェルスクリプトオプションを使用する可能性があるため、シェルスクリプトでscpを実行するのは簡単だと思います。しかし、とにかく、これがどうなるか見てみましょう。私はあなたの提案を組み込んだ後に私が使用しているかもしれない実際のシェルスクリプトで私の質問を更新しました。ご覧になり、正しく表示されているかどうか、変更したい項目がある場合はお知らせください。
SSH

+1 evalあります。
ジョセフR.

1

シェルテキスト処理ユーティリティは、主に、空白または固定文字で区切られたフィールドおよび行ごとに1つのレコードで表されるデータを操作するように設計されています。この形式は完全に異なり、簡単な方法で処理することはできません。

1つの方法は、ファイルを前処理して、簡単に処理できる形式の種類に合わせることです。大括弧と中括弧は、ここに記載されている以外の方法で使用されていないと想定しています(テキスト全体を中括弧、マシン値リストを大括弧)。

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

結果は、行ごとに1つのマシンと、レコードを区切るためのコンマです。次のスニペットは、各行のマシン名を解析し、コンマで区切られ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

@Giles:提案をありがとう。各マシンのファイルの総数を取得することもできますか?上記の同じコマンドを使用して合計数を意味しますか?上記の例のように、machineAには4つのファイルがあり、machineBにも4つのファイルがあります
SSH

@SSH私の編集を参照してください。
Gilles 'SO-悪をやめる'

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には4つのファイルがあり、machineBにも4つのファイルがあります。それも入手できますか?
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"
   ]
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.