Blaz
Blaz

Reputation: 11

Why is my code not working as I want it to?

I have this code:

total=0;
ps -u $(whoami) --no-headers | awk {'print $1'} | while read line; 
                          do vrednost=$(pmap $line | tail -n1 | column -t | cut -d" " -f3 | tr "K" " "); 
                          total=$(( vrednost + total ))
                          echo $total 
                          done
                          echo total: $total

As you can see, my code sums usage of all my processes. When I echo my total every time in while, it is working ok, but at the end... When i want total to be a value (echo total: $total) it is still zero. but before (in while) has right value.

Upvotes: 1

Views: 232

Answers (5)

chepner
chepner

Reputation: 531165

Let's cut down on the number of extra processes you need :)

declare -i total=0
for size in $( ps -u $(whoami) --no-header -o vsz ); do
    total+=$size
done
echo $total

First, use various options for ps to generate the desired list of process sizes, in kilobytes. Iterate over that list using a bash for-loop, keeping a running total in a parameter declared with the 'integer' attribute for easy arithmetic. The desired sum is now in total, ready for whatever use you need. The sum includes the memory used by the ps process itself.

Using while (Dennis' suggestion) and avoiding process substitution (William's suggestion):

ps -u $(whoami) --no-header -o vsz | { 
  while read -r var; do
    ((total+=$var))
  done
  echo $total
}

(For real one-liner, here's a dc command that I borrowed from https://stackoverflow.com/a/453290/1126841:

ps -u $(whoami) --no-header -o vsz | dc -f - -e '[+z1<r]srz1<rp'

This sum includes the memory used by the ps and dc commands themselves.)

Upvotes: 0

William Pursell
William Pursell

Reputation: 212248

Ignacio's answer is fine, but process substitution is not portable. And there is a simpler solution. You need to echo the total in the same subshell in which it is calculated:

... | { while read line; do ...; done; echo total: $total; }

Upvotes: 0

David W.
David W.

Reputation: 107040

Okay, pick and choose. You can either do it in BASH or AWK, but don't do both. You've seen a BASH example, here's an AWK example:

ps  -e -o user -o vsz | awk -v USER="$(whoami)" '
    BEGIN {TOTAL = 0}
    END {print "Total is " TOTAL}
    {
        if ($1 == USER) {
            TOTAL += $2
        }
    }
'

Awk is like a programming language that assumes a loop (like perl -n) and processes each line in the file. Each field (normally separated by whitespace) is given a $ variable. The first is $1, the second is $2, etc.

The -v option allows me to define an awk variable (in this case USER) before I run awk.

The BEGIN line is what I want to do before I run my awk script. In this case, initialize TOTAL to zero. (NOTE: This really isn't necessary since undefined variables automatically are given a value of zero). The END line is what I want to do afterwards. In this case, print out my total.

So, if the first field ($1) is equal to my user, I'll add the second field (the vsize) to my total.

All Awk programs are surrounded by {...} and they usually have single quotes around them to prevent shell interpolation of $1, etc.

Upvotes: 1

golobitch
golobitch

Reputation: 1334

Try this

#!/bin/bash
total=0;
for line in `ps -u $(whoami) --no-headers | awk {'print $1'}`; 
do 
  vrednost=$(pmap $line | tail -n1 | column -t | cut -d" " -f3 | tr "K" " "); 
      total=$(( $vrednost + $total ))
      echo $total 
done
echo "total: $total"

Upvotes: 0

Related Questions