musasabi musasabi - 1 month ago 8
Linux Question

Adding values to bash arrays

My expectation of the following code is that I'll have two arrays of shared memory ID's. One that lists the ID's with zero attachments, and one that lists the ID's with more than zero attachments.

The command ouput that I'm parsing is:

------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x6c020df2 131072 monitor 600 4276656 6
0x77020d34 4620289 usera 666 104 0
0x78020d34 4653058 usera 666 651328000 0
0x72020d34 4685827 usera 666 15808 0


And the code is as follows:

free_shmids=()
used_shmids=()

IFS=$'\n'

for line in $(sudo ipcs -m | grep '0x'); do
nattch=$(echo $line | awk '{ print $NF; }')
shmid=$(echo $line | awk '{ print $2; }')

if [ $nattch -eq "0" ]; then
free_shmids+=($shmid)
else
used_shmids+=($shmid)
fi
done

unset -v IFS


Instead, the list of free ID's is just the first free ID of the three available. I've only got one used shared memory segment here, so I assume that's failing the same way even though I can't prove it.

For reference, I'm running bash 4.3.11, so I'm pretty sure I've got access to the
+=
syntax for arrays.

EDIT:

To iterate the array of free ID's, I'm doing this:

for id in $free_shmids; do
echo $id
done


I intend to do something more complex in the body of the for loop, of course, but that exact method of iteration doesn't list every element of the array.

Answer

I bet you're doing this:

echo $free_shmid

Since that is an array, you're not using the right syntax. De-referencing an array without specifying an index will only give you the first element in the array. Do something like this:

    printf "free: %s\n" "${free_shmid[@]}"
    printf "used: %s\n" "${used_shmid[@]}"

And using a while read loop is generally preferred than using a for loop to read lines of input. For example

#!/bin/bash
data="------ Shared Memory Segments --------
key        shmid      owner      perms      bytes      nattch     status      
0x6c020df2 131072     monitor    600        4276656    6                       
0x77020d34 4620289    usera      666        104        0                       
0x78020d34 4653058    usera      666        651328000  0                       
0x72020d34 4685827    usera      666        15808      0                       "

echo "$data" | {
    read title       # first line
    read header      # second line
    # now read and process the rest
    while read -r key shmid owner perms bytes nattch status; do
        if ((nattch == 0)); then
            free_shmid+=($shmid)
        else
            used_shmid+=($shmid)
        fi
    done

    printf "free: %s\n" "${free_shmid[@]}"
    printf "used: %s\n" "${used_shmid[@]}"
}

outputs

free: 4620289
free: 4653058
free: 4685827
used: 131072

To iterate over the elements of an array, you must do this:

for elem in "${array[@]}"; do ...

Yes, all the quotes and other characters are absolutely required.