I am trying to create a BASH script that will run a command, filter the output of that command and then read the results of that output to then print only sections that meet the given requirement.

For example:

I have managed to reduce the output of the original command so that the output looks like this:

Profile: 1
PsA of Profile 1: 13
PsL of Profile 1: 15
Profile: 2
PsA of Profile 2: 0
PsL of Profile 2: 0

I am trying to write a BASH script that will read each Profile section individually, and only print the profile numbers that have PsA and PsL values of over 0.

For clarity, the output needs to be only the profile value, so in this example - 1, with 2 discarded.

It also does need to be a BASH script due to the work that I am trying to do.

I am really new to all of this, and am utterly stuck. Please help!

** EDIT ** For clarity, I am trying to work with the Volatility Framework. I am looking at the profiles that can be obtained, and currently - the exact output looks like this:

Profile suggestion (KDBGHeader): WinXPSP3x86
PsActiveProcessHead           : 0x8055a158 (31 processes)
PsLoadedModuleList            : 0x80553fc0 (122 modules)
Profile suggestion (KDBGHeader): WinXPSP2x86
PsActiveProcessHead           : 0x8055a158 (31 processes)
PsLoadedModuleList            : 0x80553fc0 (122 modules)

What I need is for the script to check the PsActiveProcessHead and PsLoadedModuleList (PsA and PsL) - specifically, the number of processes and modules found - if BOTH of those, which are shown in brackets, are above 0 then print the Profile suggestion. There may be 1 profile suggestion, there may be more - I need the script to output any profile found that has both modules and processes listed above 0.

My apologies for the unclear original question, I tried to make it simpler and adapt the answers but am still struggling. Sorry!

(To be abundantly clear, the above is just an example of the output format, they will not always both have numbers above 0 and there may be more than 2 profile suggestions)

  • 1
    Can you add the expected output format? You like to print only the profile number, or also the PsA and PsL value? Jun 4 at 11:39
  • 1
    OK, but please edit that into your question. Comments are hard to read, easy to miss and can be deleted without warning. Please edit and add the exact output you are expecting. Also, does this need to be a bash script? The shell is a very bad tool for text parsing. Did you just mean a command line solution or do you really need it to use nothing but bash for some reason?
    – terdon
    Jun 4 at 11:49
  • 1
    What do you mean by bash script? Can't we use tools like sed or awk? You just need something that can be run as part of a bash script, correct? Also, what should we do if PsA>0 but PsL<0? Should those be discarded? Will there always be exactly three lines in each profile?
    – terdon
    Jun 4 at 11:55
  • 2
    I very strongly recommend editing your question and showing a sample (suitably anonymised if necessary) of your original command's output - if you're having difficulty with this last part of it, it's very likely that what you've already written is overly complicated. With the original data, it's almost certain that a simple, efficient, one-pass solution can be written (probably involving calling sed or awk from bash)
    – cas
    Jun 4 at 12:47
  • 1
    See my updated answer. As you can see, for the updated question I suggest a totally different script. It really makes sense to give real-world examples, because others could be misleading. (-:
    – Philippos
    Jun 4 at 13:52

You can use sed with an N;D scheme:

sed -n 'N;s/PsA\( of Profile \([0-9]*\): \)[^0].*\nPsL\1[^0].*/\2/p;D'

The N appends the next line, so you always have two in the pattern space. Then you simply define a pattern with both values of the same profile and a number that does not start with zero (so values with leading zeroes will fail!). If there is a match, replace the pattern by the referenced profile number and print it (while default output is disaabled by -n option. Then start over with D, reducing the earlier line if there are two.

Update according to question update

For the real world scenario you gave, I suggest a different approach:

sed -n '/Profile suggestion/!d;h;n;/(0/d;n;//d;g;p' yourfile


  • /Profile suggestion/!d means: Drop all lines that are no profile suggestions. Stop the script here to continue with the next line.
  • h copies the profile suggestion to the hold space, so we can print it if needed
  • n continues with the next line. The current one is not printed because of the -n option to the sed command
  • /(0/d deletes this cycle if we found the pattern (0, because this means no processes
  • n;//d exactly like above, to make sure the second line also has processes
  • At this point of the script we know we had a prilfe suggestion with two lines following, each with a non-zero number of processes. g copies the hold space back to be pattern space, so we can print the suggestion
awk -F": " '
    $0~/^PsA/ && $2 > 0 
        if($2 <= 0) next; 
        sub(/[^0-9]*/, "", $1); 
        print $1
     }' data

Assuming PsA come first PsL when we find this, grab the next line of text (getline) and check if the value is greater then 0.

If this is successful, exploit the fact that the PsA and PsL record hold, it self, the profile name. Grab this from the line and print it.

Based on your edit:

awk -F": " '
    $0~/^Profile/ && h=$0 {next} 
    $1~/^PsA/ && $2~/\([^0]/ {
        if ($2~/\([^0]/) print h
    }' data

If the current line starts with Profile then save the whole header and go to the next line.

If the first field starts with PsA and inside the brackets is not 0 get the next line and do the same check, if successful print the header.


Using awk:

NOTE: input.txt is a text file containing your sample input, for testing. You can just pipe your comamnd's output directly into this awk script instead.

$ awk -F' +|\\(' '/^Profile/ {p=$0};
                  /^PsA/ {a=$5};
                  /^PsL/ {l=$5};
                  a > 0 && l > 0 && p {print p; p=""; a=0; l=0}' input.txt 
Profile suggestion (KDBGHeader): WinXPSP3x86
Profile suggestion (KDBGHeader): WinXPSP2x86

input.txt is a text file containing your sample input, for testing. You can just pipe your comamnd's output directly into this awk script instead.

This tells awk to use one-or-more spaces or an open parenthesis as the field separator (which means that the fifth field, $5, will contain the relevant processes or modules count).

The awk script reads the input file and for lines beginning with "Profile", it captures the entire line ($0) into variable p.

For lines beginning with "PsA" or "PsL", it captures the count into variables a or l respectively, from the fifth field ($5).

Finally whenever both a and l are greater than 0 and p is not empty, it prints the previously captured profile line p and resets variables a and l to zero and p to the empty string.

Alternatively, if you want only the suggested profile names (which also happen to be in the fifth field of the Profile lines):

$ awk -F' +|\\(' '/^Profile/ {p=$5};
                  /^PsA/ {a=$5};
                  /^PsL/ {l=$5};
                  a > 0 && l > 0 && p {print p; p=""; a=0; l=0}' input.txt 

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy