2

I'm trying to write a command that gives me some information about a linux system. The command should be a one liner. It should represent the total amount of interrupts, processes and context-switches.

I'm quite new to the linux world, so this isn't an easy thin for me. So far, I found this:

cat /proc/stat | grep -E 'ctxt|intr|processes' | \
 perl -nle 'if ($line == /^intr (.*)/) {print $_} else {print $1}'

The problem is in the last part, the else. I'm not interessed in the value of $1, but I should know the sum of the items in $1.

$1 should contain something like:

8522774 17 6 0 0 0 0 2 0 1 0 1435117 21 103 0 84742 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0

But I've no idea how I could get the sum of all these numbers. I believe I should pass it to bc, but I've no idea how to manage this.

Mat
  • 202,337
  • 40
  • 393
  • 406
Write Down
  • 158
  • 2
  • 5
  • 15
  • 1
    That's a redundant use of `cat`. Perhaps you should show input and expected output. That will make this about 10 times easier to help you with. – TLP Feb 13 '13 at 13:01

3 Answers3

7

Your one-liner:

cat /proc/stat | grep -E 'ctxt|intr|processes' | \
perl -nle 'if ($line == /^intr (.*)/) {print $_} else {print $1}'

The problem with this line is that perl has no implicit variable $line, it is called $_. Also, the regex is applied to strings with the binding operator =~, not the numeric equality operator ==. Your if-statement is reversed, if the regex doesn't match, you don't want to print $1, because that is the string that is captured by parentheses in your last regex.

You also do not need to use cat or grep, since perl can handle this just fine.

perl -nlwe 'if (/ctxt|processes/) { print } 
            elsif (/^intr (.*)/ { print $1 }' /proc/stat

This one-liner should do exactly what your line did, in that it "greps" the lines that match ctxt|intr|processes, and prints only the match for the "intr" lines.

If you want to print the sum of certain numbers, which feels like a whole new question to me, you can make use of the sum() subroutine from the List::Util module in perl. E.g.:

perl -MList::Util=sum -nlwe 'if (/ctxt|processes/) { print } 
            elsif (/^intr (.*)/ { print sum split ' ', $1 }' /proc/stat

In this case, you'll need to rely on your captured string to contain only numbers. sum() takes a list of numbers, which is why we need to split the input.

TLP
  • 66,756
  • 10
  • 92
  • 149
3

How about this:

awk '/^intr/ {for(i=2;i<=NF;++i) sum+=$i; print "intr",sum}
     /^processes|ctxt/ {print}' /proc/stat

You usually don't have to call bc from perl, but maybe there is a reason for your overall approach being "the more processes, the better".

Anton Kovalenko
  • 20,999
  • 2
  • 37
  • 69
-3
cat /proc/stat | grep -E 'ctxt|intr|processes' | 
    perl -nle 'if ($line == /^intr (.*)/) {print $_} else {print $1}' | 
    sed 's/ /+/g' | bc
TLP
  • 66,756
  • 10
  • 92
  • 149
  • 3
    I did not downvote, but the perl part is still broken, you still have a redundant use of cat, and you tack on yet another process on the end instead of handling it with perl. – TLP Feb 13 '13 at 13:09