LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Software (https://www.linuxquestions.org/questions/linux-software-2/)
-   -   Load variables into an array (https://www.linuxquestions.org/questions/linux-software-2/load-variables-into-an-array-935385/)

xwassyx 03-19-2012 09:03 PM

Load variables into an array
 
this is a little difficult to explain in the subject line so if its confusing im srry. but basically I have a file that has some information in it.
Quote:

adapter 0
virtual disk 0
just some stuff
physical disk 0:0
some more stuff
physical disk 0:1
physical disk 0:2
this is even more
physical disk 0:3
virtual disk 1
what even more
physical disk 1:0
physical disk 1:1
What I'm trying to do is take the relevant information in its correct format and then output that to another file, kind of like a sort if that makes sense. Here is my script so far.

Quote:

#!/bin/bash

v=0
a=0
d=0
IFS=$'\n'

grep "adapter" /root/test.txt | awk '{ print $1 }' > /tmp/test1.tmp
lineRCA=( $(wc -l /tmp/test1.tmp | awk '{ print $1}') )
while [ $a -lt $lineRCA ]
do
Adap=( $(grep "adapter" /root/test.txt) )
echo "${Adap[a]}" >> /root/test.tmp
grep "virtual" /root/test.txt | awk '{ print $1 }' > /tmp/test2.tmp
lineRCV=( $(wc -l /tmp/test2.tmp | awk '{ print $1}') )
while [ $v -lt $lineRCV ]
do
Vdisk=( $(grep "virtual" /root/test.txt) )
echo "${Vdisk[v]}" >> /root/test.tmp
grep "physical" /root/test.txt | awk '{ print $1 }' > /tmp/test3.tmp
lineRCP=( $(wc -l /tmp/test3.tmp | awk '{ print $1}') )
while [ $d -lt $lineRCP ]
do
Pdisk=( $(grep "physical" /root/test.txt) )
echo "${Pdisk[d]}" >> /root/test.tmp
((d++))
done
((v++))
done
((a++))
done
The issue is it outputs as so.
Quote:

adapter 0
virtual disk 0
physical disk 0:0
physical disk 0:1
physical disk 0:2
physical disk 0:3
physical disk 1:0
physical disk 1:1
virtual disk 1
But I need it to output like
Quote:

adapter 0
virtual disk 0
physical disk 0:0
physical disk 0:1
physical disk 0:2
physical disk 0:3
virtual disk 1
physical disk 1:0
physical disk 1:1
my theory is kinda sound but sadly not working and I'm not sure what I'm doing wrong. And yes I realise my script is not very eligant and probably caveman like but I'm still learning bash.

catkin 03-19-2012 11:48 PM

Let's start by putting the code in CODE tags and indenting it to make it more readable:
Code:

#!/bin/bash

v=0
a=0
d=0
IFS=$'\n'

grep "adapter" /root/test.txt | awk '{ print $1 }' > /tmp/test1.tmp
lineRCA=( $(wc -l /tmp/test1.tmp | awk '{ print $1}') )
while [ $a -lt $lineRCA ]
do
    Adap=( $(grep "adapter" /root/test.txt) )
    echo "${Adap[a]}" >> /root/test.tmp
    grep "virtual" /root/test.txt | awk '{ print $1 }' > /tmp/test2.tmp
    lineRCV=( $(wc -l /tmp/test2.tmp | awk '{ print $1}') )
    while [ $v -lt $lineRCV ]
    do
        Vdisk=( $(grep "virtual" /root/test.txt) )
        echo "${Vdisk[v]}" >> /root/test.tmp
        grep "physical" /root/test.txt | awk '{ print $1 }' > /tmp/test3.tmp
        lineRCP=( $(wc -l /tmp/test3.tmp | awk '{ print $1}') )
        while [ $d -lt $lineRCP ]
            do
            Pdisk=( $(grep "physical" /root/test.txt) )
            echo "${Pdisk[d]}" >> /root/test.tmp
            ((d++))
        done
        ((v++))
    done
    ((a++))
done

The input shown is already ordered so why not process the file line by line and use bash pattern matching to avoid all those greps and awks? Something like
Code:

#!/bin/bash

while read line
do
    case $line in
        adapter* | virtual* | physical* )
            echo "$line"
    esac
done < input.txt


jimtony 03-20-2012 12:57 AM

You should try catkin's codes, your code is too complicated.

xwassyx 03-20-2012 07:07 AM

Quote:

Originally Posted by jimtony (Post 4631220)
You should try catkin's codes, your code is too complicated.

Apologies catkin on the indents, I think that was from my copy paste. And yes I do realise that my code may be complicated thanx for the help, truly =)

Basically in my example it is already in order and it is in what I'm trying to accomplish ultimately. But the ultimate goal is to read each item into a variable, or should I say line I grep for, then be able to place those where I need.

Honestly I realise my code again is caveman like but as I already said I'm trying to learn and understand.

pan64 03-20-2012 07:12 AM

do you really want to do it in bash? using perl or awk will make it much easier.

xwassyx 03-20-2012 07:14 AM

Quote:

Originally Posted by pan64 (Post 4631462)
do you really want to do it in bash? using perl or awk will make it much easier.

Perl will create more dependencies, also as I am limited on knowledge to programming, so it may be out of my league. As far as I understand awk will load each word into a variable right? not a sentence?

pan64 03-20-2012 07:31 AM

both can handle associative arrays, something like this:
var[name] = value
"name" and "value" can be text
and you can implement any kind of sort function

catkin 03-20-2012 07:49 AM

Quote:

Originally Posted by xwassyx (Post 4631460)
Apologies catkin on the indents, I think that was from my copy paste. And yes I do realise that my code may be complicated thanx for the help, truly =)

Basically in my example it is already in order and it is in what I'm trying to accomplish ultimately. But the ultimate goal is to read each item into a variable, or should I say line I grep for, then be able to place those where I need.

Honestly I realise my code again is caveman like but as I already said I'm trying to learn and understand.

You copy-paste was fine but it needs to go in CODE tags to retain indentation -- most easily by going into Advanced editing mode and using the # button.

My suggestion could be adapted to load the data into variables. Don't know exactly what you want so this is only an idea to parse out what you might want from the lines:
Code:

#!/bin/bash

while read line
do
    case $line in
        adapter* )
            adapter_n=${line## }
        virtual* )
            virtual_n=${line## }
        physical* )
            virtual_n=${line## }
    esac
done < input.txt


xwassyx 03-20-2012 07:55 AM

Quote:

Originally Posted by catkin (Post 4631501)
You copy-paste was fine but it needs to go in CODE tags to retain indentation -- most easily by going into Advanced editing mode and using the # button.

My suggestion could be adapted to load the data into variables. Don't know exactly what you want so this is only an idea to parse out what you might want from the lines:
Code:

#!/bin/bash

while read line
do
    case $line in
        adapter* )
            adapter_n=${line## }
        virtual* )
            virtual_n=${line## }
        physical* )
            virtual_n=${line## }
    esac
done < input.txt


Hmmm it may just work jimmy!!! basically and again this may be a long way of getting it done. I'm trying to parse the info from a log to an xml file so a can format it the way I need in an html document. LOL yes going around my elbow to get to my thumb but this may just work.

David the H. 03-20-2012 09:06 AM

To load a seqence into an array, simply use the arr+=() syntax. Every "word" inside the brackets will be added to the array as a new element.

Alternately you can use an incrementing counter variable.

Code:

#!/bin/bash

while read line; do

        case $line in

                adapter* ) adapter+= ( "${line## }" ) ;;
                virtual* ) virtual[n1++]="${line## }" ;;
                physical* ) physical[n2++]="${line## }" ;;

        esac

done < input.txt

printf "%s\n" "${adapter[@]}" "${virtual[@]}" "${physical[@]}"

BTW, just to let you know, there's a small "gotcha" that you might encounter when using a while+read loop. If the final line doesn't end with a newline character, the sub-commands won't execute.

http://mywiki.wooledge.org/BashFAQ/0...al_newlines.21

You'll have to either ensure that the file is formatted properly first, or process the last variable value separately afterwards.

xwassyx 03-20-2012 09:44 AM

Quote:

Originally Posted by David the H. (Post 4631573)
To load a seqence into an array, simply use the arr+=() syntax. Every "word" inside the brackets will be added to the array as a new element.

Alternately you can use an incrementing counter variable.

Code:

#!/bin/bash

while read line; do

        case $line in

                adapter* ) adapter+= ( "${line## }" ) ;;
                virtual* ) virtual[n1++]="${line## }" ;;
                physical* ) physical[n2++]="${line## }" ;;

        esac

done < input.txt

printf "%s\n" "${adapter[@]}" "${virtual[@]}" "${physical[@]}"

BTW, just to let you know, there's a small "gotcha" that you might encounter when using a while+read loop. If the final line doesn't end with a newline character, the sub-commands won't execute.

http://mywiki.wooledge.org/BashFAQ/0...al_newlines.21

You'll have to either ensure that the file is formatted properly first, or process the last variable value separately afterwards.

That worked perfect you are the man!!!

David the H. 03-22-2012 12:21 PM

By the way, here's another option for you.

bash's new (v.4+) mapfile command, and process substitution, can be used to store the output lines of a command into an array.

You can also use process substitution for things like running the array through sort.

Code:

mapfile -t adapter < <( grep '^adapter' input.txt )
mapfile -t virtual < <( grep '^virtual' input.txt )
mapfile -t physical < <( grep '^physical' input.txt )

sort < <( printf "%s\n" "${adapter[@]}" )
sort < <( printf "%s\n" "${virtual[@]}" )
sort < <( printf "%s\n" "${physical[@]}" )

Of course you can also sort the output of grep directly before sending it to mapfile.

xwassyx 03-22-2012 01:16 PM

actually I realised I was making my process way to confusing and went much simpler. Basically removed the array idea and went to the basic layout you had and output the way I need. The reason I thought I needed an array is because I was putting the data in xml tags. Which I later realised was not very sound and caused lots of issue. Simply outputting $line from the read between the tags worked beautifully.

Lesson learned stick to simple stupid.


All times are GMT -5. The time now is 01:55 PM.