3

I run the following command.

ps -e -o args | grep destiny | grep UNIX

I receive the following output.

/path/to/destiny -r -m UNIX -t TCP -p 1501

What command can I use the get the value of the printed arguments (for example -m or -t or -p)? I would like to achieve the following.

ps -e -o args | grep destiny | grep UNIX | <someCommand> -p this should print 1501

ps -e -o args | grep destiny | grep UNIX | <someCommand> -m this should print UNIX

ps -e -o args | grep destiny | grep UNIX | <someCommand> -t this should print TCP

Please note that -p, -m or -t may switch columns so printing with awk and choosing column by number is not an option.

Some more facts so that the parsing gets easier (I know it's possible I just lack the tooling knowledge).

  • if an option is not present an empty string will be returned
  • options that will be parsed will always have an argument/a value in this particular case
2

How about using sed:

ps -e -o args | grep -e 'destiny.*UNIX' | sed -e 's/.*-t\s\([A-Z0-9]*\).*/\1/'
ps -e -o args | grep -e 'destiny.*UNIX' | sed -e 's/.*-p\s\([A-Z0-9]*\).*/\1/'
ps -e -o args | grep -e 'destiny.*UNIX' | sed -e 's/.*-m\s\([A-Z0-9]*\).*/\1/'

sed -e 's/.*-t\s\([A-Z0-9]*\).*/\1/'

  • s/search for/replace with/options
  • s is to search.
  • .* matches any/all character(s) until we get to the "-t".
  • \s matches any whitespace.
  • ( begins a capture.
  • [A-Z0-9]* matches any capital letter and any number of any length.
  • ) ends the capture.
  • .* matches the remainder of the characters in the line (if there are any).
  • \1 replaces everything with the capture.
  • This method will fail when getting the value of last option (like -p 1501 in my question). How do I express \s (whitespace) OR $ (end of line) at the end? – Tony Stark Jun 2 '15 at 20:34
  • No it won't. There is no white space at the end of the sed search. .* is any number of characters including nothing at all. – h3rrmiller Jun 2 '15 at 20:39
  • Sorry, my bad. The string I tested was not upper case. – Tony Stark Jun 2 '15 at 20:43
  • There was a typo in my grep statement. The comma should've been a period. Sorry about that – h3rrmiller Jun 2 '15 at 20:45
5

That is not possible in general because only the command itself knows how to parse its own arguments. Taking your example:

/path/to/destiny -r -m UNIX -t TCP -p 1501

-p could be an option that takes no argument (like a boolean: it enables or disables some behaviour) in which case 1501 would be a positional argument (like a filename or something). Or -p could be an option that takes an argument, and its argument is 1501. There's no way to know which it is!

The argument vector is just a list of zero or more strings. There is no meaning attached to those strings indicating which ones are options, which ones are arguments to those options, and which ones are non-option arguments.

Even the -r option in your example cannot be generically parsed for certain. Given that -r is followed immediately by another string that begins with -, it's overwhelmingly likely that -r is an option that takes no argument (like a boolean that enables or disabled some behaviour) but actually that's not 100% certain. -r could be an option that takes an argument and -m would be its argument. Or the command might not follow normal UNIX conventions at all, and -r is not an option at all!

2

You can use grep:

~$ echo "/path/to/destiny -r -m UNIX -t TCP -p 1501" | grep -oP -- '-t \K[^ ]+'
TCP
~$ echo "/path/to/destiny -r -m UNIX -t TCP -p 1501" | grep -oP -- '-p \K[^ ]+'
1501

(you may have/want to use things like \s instead of one space: grep -oP -- '-p\s\K[^\s]+')

The -o means "print only the matching", the \K will reset the start.

Note that this will only handle simple cases (see Celada's answer for why).

Another way, using look-behind:

grep -oP -- '(?<=-p )[^ ]+'
1

Here's a python one-liner. (I'm using python because perl and awk don't have a simple way to get the position of a value in a list.)

ps -eo args | grep '/path/to/destiny' | 
     python -c 'x=input().split(); print(x[ x.index("-p")+1 ])'

It will work as long as the arguments you're trying to extract do not contain spaces.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.