LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Linux - Newbie (https://www.linuxquestions.org/questions/linux-newbie-8/)
-   -   Getting a certain Parameter from the command-line of a foreign process in bash... (https://www.linuxquestions.org/questions/linux-newbie-8/getting-a-certain-parameter-from-the-command-line-of-a-foreign-process-in-bash-921210/)

nachaz 12-30-2011 06:04 AM

Getting a certain Parameter from the command-line of a foreign process in bash...
 
Hi everyone,

until now I used a certain command to extract positional arguments from the command line of certain processes I want to monitor:

Code:

#!/bin/bash
ps aux|grep Dxxx.home|grep -v grep|awk '{print "\tConf: " $19, "\tProcess: " $25, "\tPID: " $2}'

Here is what it does exaclty:
"ps aux" returns all processes including their command-line
"grep Dxxx.home" returns only the processes I'm interested in
"grep -v grep" excludes grep commandos...
"awk '{print "\tConf: " $19, "\tProcess: " $25, "\tPID: " $2}'" returns the 19th, the 25th as well as the 2nd column of the output

Regrettably returning the 19th and the 25th parameter doesn't not work anymore because the processes are now called using a different number of command line arguments. So I need a way to find and print the values following certain arguments, e.g:
instead of $25 I'd have to find the argument following the "-p"-Argument
instead of $17 I'd have to find the argument following the "-c"-Argument

Does anyone know how to accomplish this in a single bash-script?

Thanks in advance!

David the H. 12-31-2011 11:25 AM

Could you give us an example of the ps output that needs to be processed? It's kind of hard to test solutions when you don't know what the input looks like.

In any case, the original command is a fairly good example of Useless Use of grep, as awk is perfectly capable of handling all line filtering internally.

It looks like the modified version would have to iterate through every field on the line, check it for the patterns you want, and output the value of a matching field + 1. Certainly doable, but it would require a bit of testing.

Finally, have you taken the time to look into all the options of ps? It's possible that you may already be able to get it to output only what you want, or at least format the lines in a way that's easier to parse.


To give you a head start, here are a few useful awk references:

http://www.grymoire.com/Unix/Awk.html
http://www.gnu.org/software/gawk/man...ode/index.html
http://www.pement.org/awk/awk1line.txt
http://www.catonmat.net/blog/awk-one...ined-part-one/

nachaz 01-02-2012 04:01 AM

Well, here is an example ps-output:
Code:

xxxx    24824  154  6.6 6887532 2190560 pts/1 Sl  10:41  16:25 /usr/bin/java -server -Xms256m -Xmx4096m -XX:MaxPermSize=2048m -Dxxxx.home=/opt/xxxx/App -Djava.util.logging.config.file=/opt/xxxx/App/conf_xxxxTitan/logging.properties de.comp.xxxx.services.ProcessRunner -c /opt/xxxx/App/conf_xxxxTitan -u PROC_KOMM_USER -k xx -p KOMM -f
xxxx    24842  336 11.3 7013100 3749568 pts/1 Sl  10:41  35:40 /usr/bin/java -server -Xms256m -Xmx4096m -Dxxxx.home=/opt/xxxx/App -Djava.util.logging.config.file=/opt/xxxx/App/conf_xxxxTitan/logging.properties de.comp.xxxx.services.ProcessRunner -c /opt/xxxx/App/conf_xxxxTitan -u PROC_PROC_USER -k xx -p PROC -f
xxxx    22375  131  0.3 6649572 129588 pts/1  Sl  10:53  0:09 /usr/bin/java -server -Xms256m -Xmx4096m -Dxxxx.home=/opt/xxxx/App -Djava.util.logging.config.file=/opt/xxxx/App/conf_xxxxCallisto/logging.properties de.comp.xxxx.services.ProcessRunner -c /opt/xxxx/App/conf_xxxxCallisto -u PROC_KOMM_USER -k xx -p KOMM -f
xxxx    22376  128  0.4 6657764 134288 pts/1  Sl  10:53  0:08 /usr/bin/java -server -Xms256m -Xmx4096m -XX:MaxPermSize=2048m -Dxxxx.home=/opt/xxxx/App -Djava.util.logging.config.file=/opt/xxxx/App/conf_xxxxCallisto/logging.properties de.comp.xxxx.services.ProcessRunner -c /opt/xxxx/App/conf_xxxxCallisto -u PROC_PROC_USER -k xx -p PROC -f

Thanks for the awk-references - didn't know it was that powerful.

I'm going to give it a shot and post the solution - if I can do it.

nachaz 01-02-2012 04:54 AM

This is the solution to the problem:

Code:

ps aux|grep Dxxx.home|grep -v grep|awk '{ for (i=0;i<=NF;i++ ) { if ( $i=="-c" ) { config_arg=i+1 } } for (i=0;i<=NF;i++ ) { if ( $i=="-p" ) { process_arg=i+1 } }  printf "\t Conf: " $config_arg "\tProcess: " $process_arg "\tPID: " $2 "\n" }'
The beautification of the awk-code:
Code:

{
  # Loop over all arguments (NF is the argument-count)
  for (i=0;i<=NF;i++ )
  {
    # If the argument is -c...
    if ( $i=="-c" )
    {
      #save it's position into the variable config_arg and add one
      config_arg=i+1
    }
  }
 
  # Another loop over all arguments...
  for (i=0;i<=NF;i++ )
  {
    # If the argument is -p...
    if ( $i=="-p" )
    {
      #save it's position into the variable process_arg and add one
      process_arg=i+1
    }
  }
     
  # Do the output. Precede vars with $ to get the arguments and not just
  # their position...
  printf "\t Conf: " $config_arg "\tProcess: " $process_arg "\tPID: " $2 "\n"
}

The comments are telling you what the code is doing...

Thank's again for the Doc and especially the "Famous one-liners"!

David the H. 01-02-2012 03:52 PM

Well done! You learn quickly.

You don't need two separate loops, however. You can process both variables in one pass. Your printf function was using the wrong syntax too.

I've also looked a bit at ps, and you can indeed tell it to output only the fields you want.

First the awk script, which I set to be stand-alone. It's mostly just a modified version of what you posted .
Code:


#!/usr/bin/awk -f

{
        if ( $0 ~ /Dxxx.home/ ) {
                # Loop over all arguments (NF is the argument-count)
                for ( i=0 ; i<=NF ; i++ ) {
                        # If the argument is either -c or -p save the position of the next argument into a variable
                        if ( $i == "-c" ) { config_arg = i+1 }
                        if ( $i == "-p" ) { process_arg = i+1 }
                }

                # Do the output. Precede vars with $ to get the arguments and not just their position...
                printf "\tConf: %s\tProcess: %s\tPID: %s\n" , $config_arg , $process_arg , $1
        }
}

And to run it:

Code:

ps -eo "pid cmd" | script.awk
( ps also has a -C option, which matches the name of a process. But I don't know if it would work in this case as the process name appears to be variable. )


In fact, if you want, you can use getline to incorporate the command input straight into the awk script itself, and just run it stand-alone.

Code:


#!/usr/bin/awk -f

BEGIN{
        while ( ( "ps -eo 'pid cmd'" ) | getline ) {

                if ( $0 ~ /Dxxx.home/ ) {
                        # Loop over all arguments (NF is the argument-count)
                        for ( i=0 ; i<=NF ; i++ ) {
                                # If the argument is either -c or -p save the position of the next argument into a variable
                                if ( $i == "-c" ) { config_arg = i+1 }
                                if ( $i == "-p" ) { process_arg = i+1 }
                        }

                        # Do the output. Precede vars with $ to get the arguments and not just their position...
                        printf "\tConf: %s\tProcess: %s\tPID: %s\n" , $config_arg , $process_arg , $1
                }
        }
}



All times are GMT -5. The time now is 02:29 PM.