फ़ाइल को विभाजित करें और इसे संबंधित डेटा संरचना में डालें?


10

मेरे पास एक फाइल है जिसमें नीचे सिंगल लाइन है:

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

जिसमें मेरे दो डेटासेट हैं:

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

अब, मुझे उपरोक्त फ़ाइल को पढ़ने और इसे इस तरह से विभाजित करने की आवश्यकता है कि मैं प्रत्येक मशीन की जानकारी को ऊपर बताए अनुसार निकाल सकूं और इसे कुछ डेटा संरचना में संग्रहीत कर सकूं।

वर्तमान में, मैं भ्रमित हूँ कि कौन सी डेटा संरचना मुझे बैश शेल स्क्रिप्ट में उपयोग करनी चाहिए। अगर मैं जावा में ऐसा कर रहा था, तो मैं उपयोग करूंगा Map<String, Set<String>>लेकिन मुझे यकीन नहीं है कि मुझे शेल स्क्रिप्ट में क्या उपयोग करना चाहिए।

और इसे कुछ डेटा संरचना में संग्रहीत करने के बाद, मुझे इसे पुनरावृत्त करने और परिणाम का प्रिंट आउट करने की आवश्यकता है।

मैं नीचे दी गई शेल स्क्रिप्ट का उपयोग करके उपरोक्त फ़ाइल को पढ़ने में सक्षम हूं:

#!/bin/bash

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

लेकिन मुझे यकीन नहीं है कि उपरोक्त लाइन डेटा को इस तरह से कैसे विभाजित किया जाए ताकि मैं प्रत्येक मशीन को सूचित कर सकूं और फिर इसे कुछ डेटा संरचना में संग्रहीत कर सकूं?

अपडेट करें:-

नीचे मेरी शेल स्क्रिप्ट है जो मुझे ग्लेन द्वारा दिए गए सुझाव के बाद मिली है -

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

बैश डेटा संरचनाएं 2-आयामी सरणियों के लिए बहुत अल्पविकसित हैं। क्या आप वाकई इस उपकरण का उपयोग करना चाहते हैं?

बैश और ग्नू ग्रीप के साथ, आप यह अरुचिकर गड़बड़ कर सकते हैं:

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

यह बहुत नाजुक है। मैं पर्ल का उपयोग कुछ इस तरह से करूँगा: अभी भी बदसूरत लेकिन अधिक संक्षिप्त

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 करना आसान होगा। लेकिन वैसे भी, देखते हैं कि यह कैसे निकलता है। मैंने अपने प्रश्न को वास्तविक शेल स्क्रिप्ट के साथ अद्यतन किया है जो मैं आपके सुझाव को शामिल करने के बाद उपयोग कर सकता हूं। कृपया एक नज़र डालें और मुझे बताएं कि क्या यह सही लगता है और यदि कोई ऐसी चीज़ है जिसे आप संशोधित करना चाहते हैं तो मुझे भी बताएं।
एसएसएच

evalवहाँ के साथ +1 सुंदर चालाक चाल ।
जोसेफ आर।

1

शेल टेक्स्ट प्रोसेसिंग यूटिलिटीज़ मुख्य रूप से एक रिकॉर्ड प्रति पंक्ति और व्हाट्सएप या एक निश्चित वर्ण द्वारा अलग किए गए फ़ील्ड के साथ प्रतिनिधित्व किए गए डेटा में हेरफेर करने के लिए डिज़ाइन की गई हैं। यह प्रारूप पूरी तरह से अलग है और आप इसे सीधे तरीके से संसाधित नहीं कर पाएंगे।

एक तरीका यह है कि फ़ाइल को उस प्रकार के प्रारूप में फिट किया जाए जिसे आसानी से संसाधित किया जा सके। मुझे लगता है कि कोष्ठक और ब्रेसिज़ का उपयोग यहां चित्रित के अलावा किसी भी तरह से नहीं किया गया है (पूरे पाठ के चारों ओर ब्रेसिज़, मशीन मूल्य सूचियों के चारों ओर कोष्ठक)।

<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 

निम्नलिखित बैश-विशिष्ट स्निपेट मानों को एक सरणी में रखता है।

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

@ गिल्स: सुझाव के लिए धन्यवाद। क्या प्रत्येक मशीनों के लिए कुल फ़ाइलों की संख्या प्राप्त करना भी संभव है? मतलब उपरोक्त कमांड का उपयोग करके कुल गणना? जैसे, उपर्युक्त उदाहरण के लिए, मशीनए के पास चार फाइलें हैं और मशीनबी के पास भी चार फाइलें हैं
एसएसएच

@SSH मेरा संपादन देखें
गाइल्स का 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]

धन्यवाद जॉन। क्या प्रत्येक मशीन के लिए कुल फ़ाइलों की संख्या प्राप्त करना संभव है। जैसे, उपर्युक्त उदाहरण के लिए, मशीनए के पास चार फाइलें हैं और मशीनबी के पास भी चार फाइलें हैं। क्या ऐसा हो पाना संभव है?
एसएसएच

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"
   ]
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.