0

I'm writing what should be a simple function that takes the output of /proc/[pid]/maps and writes it to CSV. I'd like to write the total size of all the maps at the bottom.

Here's the function:

output_MAPS ()
{

    {
    local total=0 
    echo "total , size , size_hex , start , end , perms , offset , dev , inode , path"
    echo "$1" | while read line ; do
        local start="$( echo "$line"| awk '{print $1}'| awk 'BEGIN { FS="-" } { print $1 }' )"
        local end="$( echo "$line"| awk '{print $1}'| awk 'BEGIN { FS="-" } { print $2 }' )"
        local perms="$( echo "$line"| awk '{print $2}' )"
        local offset="$( echo "$line"| awk '{print $3}' )"
        local dev="$( echo "$line"| awk '{print $4}' )"
        local inode="$( echo "$line"| awk '{print $5}' )"
        local path="$( echo "$line"| awk '{print $6}' )"
        local size=$(( 0x$end - 0x$start ))
        local size_hex="$( printf "%X" "$size")"
        local tot_size=$(( $tot_size + $size ))
        echo "$tot_size , $size , $size_hex , $start , $end , $perms , $offset , $dev , $inode , $path"
        total="$tot_size"
    done
    echo "TOTAL $total :: $tot_size" 
    }> "$outputdir/$4_$3_$2.csv"
}

and here's the last few lines of output:

114282496 , 20480 , 5000 , 2aaab14b0000 , 2aaab14b5000 , rw-p , 2aaab14b0000 , 00:00 , 0 ,
170688512 , 56406016 , 35CB000 , 2aaab14b5000 , 2aaab4a80000 , r--p , 00000000 , 08:02 , 3702398 , /usr/lib/locale/locale-archive
170717184 , 28672 , 7000 , 2aaab4a80000 , 2aaab4a87000 , r--s , 00000000 , 08:02 , 4000735 , /usr/lib64/gconv/gconv-modules.cache
170721280 , 4096 , 1000 , 2aaab4a87000 , 2aaab4a88000 , rw-p , 2aaab4a87000 , 00:00 , 0 ,
170811392 , 90112 , 16000 , 7ffffffe9000 , 7ffffffff000 , rw-p , 7ffffffe8000 , 00:00 , 0 , [stack]
179200000 , 8388608 , 800000 , ffffffffff600000 , ffffffffffe00000 , ---p , 00000000 , 00:00 , 0 , [vsyscall]
TOTAL 0 ::

We can see from the first column that I'm calculating the total, but I just can't get the value out of the loop, even when I assign it to a variable declared outside. So what stupid thing am I doing?

1
  • Note that local doesn't work quite like you expect it to (although it won't affect the code you've written). A variable can only be made local to a function; a new scope is not defined by constructs such as a command group or a while loop. Commented Sep 3, 2013 at 11:19

1 Answer 1

2

The problem is that you are piping into the while loop. The loop is executed in a subshell and when the loop finishes all variables defined within it are discarded. That's why you see that tot_size is blank.

Instead of a pipe, use redirection as shown below:

while read line ; do
    local start="$( echo "$line"| awk '{print $1}'| awk 'BEGIN { FS="-" } { print $1 }' )"
    local end="$( echo "$line"| awk '{print $1}'| awk 'BEGIN { FS="-" } { print $2 }' )"
    local perms="$( echo "$line"| awk '{print $2}' )"
    local offset="$( echo "$line"| awk '{print $3}' )"
    local dev="$( echo "$line"| awk '{print $4}' )"
    local inode="$( echo "$line"| awk '{print $5}' )"
    local path="$( echo "$line"| awk '{print $6}' )"
    local size=$(( 0x$end - 0x$start ))
    local size_hex="$( printf "%X" "$size")"
    local tot_size=$(( $tot_size + $size ))
    echo "$tot_size , $size , $size_hex , $start , $end , $perms , $offset , $dev , $inode , $path"
    total="$tot_size"
done <<< "$1"

See: BashFAQ/024 for a detailed explanation of this issue.

Sign up to request clarification or add additional context in comments.

1 Comment

Oooh! Thanks for that: I didn't realise the loop was in a subshell. I like learning things :-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.