grep a variable containing special characters - linux

i'm new to bash scripting and i have to determine if a process is running in a linux environment.
Actually i use the follow command to do the job:
#ps -ef | awk '{print substr($0, index($0,$8))}' | grep -v grep | grep -w -F $PROCESSNAME
where
awk '{print substr($0, index($0,$8))}'
allow me to ignore UID PID PPID C STIME TTY TIME fields and
grep -v grep
allow me to ignore the row that contains the command itself. So at this point i have a list of all processes running on the system.
Finally:
grep -w -F $PROCESSNAME
read a variable which contains the name of the process that i want to check.
For what i understand the full command should return only the row that has the exact value of $PROCESSNAME
Actually this doesn't works correctly for processes that follow the pattern "[processname]", and probably also for other patterns.
For example to simplify, if i have a running process named "[vmmemctl]" and i run:
#ps -ef | grep -v grep | grep -w -F "vmmemctl]"
it actually returns a result:
#root 615 2 0 Feb26 ? 00:01:00 [vmmemctl]
but the actual process name in the command is different from the process name in the result.
What is the correct command that doesn't have this behavior?
Thank you

awk to the rescue!
ps -ef | awk '$8=="[command]"{NF=8;print}'
or
ps -ef | awk -v c="vmmemctl]" '$8==c{NF=8;print}'
note that this is for an exact match not pattern.
since this is an exact match the command can have spaces and other special chars in it (it's not pattern match but string equality). Using your variable name it will look like this
ps -ef | awk -v c="$PROCESSNAME" '$8==c{NF=8;print}'

Related

Capture pid of a process started from a terminal with its unique command line

I'm trying to get the process id of multiple processes run from a multiple tmux windows. Each processes started have their unique command line. I think only the command line is unique as there can be multiple processes with same name. what i did currently is
process_pid=$(ps --no-headers aux | grep "${process_cmd_line}" | grep -v grep | awk '{print $2}' | tr '\n' '')
This works for me. But i want to know if this is the correct approach to do this. I know there are output format specifiers. Any example to do the same with the format specifier or an improvement over the code above?

Why does `ps | grep -o RandomString` always print `RandomString`? [duplicate]

I am using this command to get the process ID of another command:
ps aux | grep 7000.conf | awk '{print $2}'
This will return two PIDs:
7731
22125
I only want the first one. The second is the PID for grep in the above command. Thanks in advance to any one who knows how to alter the above command to return just the first pid.
p.s. open to a new command that does the same thing
In this particular case, escaping the . to what I assume it was meant to do should work:
ps aux | grep '7000\.conf' | awk '{print $2}'
Alternatively, exclude grep:
ps aux | grep 7000.conf | grep -v grep | awk '{print $2}'
ps aux | grep "[7]000.conf" will work as well.

AWK - Remove last item out of list

I'm trying to get the PID's of a certain service. I'm trying to do that with the following command:
ps aux | grep 'DynamoDBLocal' | awk '{print $2}'
Gives output:
1021
1022
1161
This returns me 3 PID's, 2 of the service that I want, and 1 for the grep it just did. I would like to remove the last PID (the one from the grep) out of the list.
How can I achieve this?
Just use pgrep, it is the correct tool in this case:
pgrep 'DynamoDBLocal'
Using grep -v:
ps aux | grep 'DynamoDBLocal' | grep -v grep | awk '{print $2}'
If you have pgrep in your system
pgrep DynamoDBLocal
You can say:
ps aux | grep '[D]ynamoDBLocal' | awk '{print $2}'
With a single call to awk
ps aux | awk '!/awk/ && /DynamoDBLocal/{print $2}'
Try pidof, it should give you the pid directly.
pidof DynamoDBLocal
Answering the original question: How to remove lines from output:
ps aux | grep 'DynamoDBLocal' | awk '{print $2}' | head --lines=-1
head allows you to view the X (default 10) first lines of whatever comes in. Given a value X with minus prepended it shows all but the last X lines. The 'inverse' is tail, btw (when you are interested in the last X lines).
However, given your specific problem of looking for PIDs, I recommend pgrep (perreals answer).
I'm not sure that ps aux | grep '...' is the right way.
But assuming that it is right way, you could do
ps aux | grep '...' | awk '{ if (prev) print prev; prev=$2 }'

How to specify more spaces for the delimiter using cut?

Is there any way to specify a field delimiter for more spaces with the cut command? (like " "+) ?
For example: In the following string, I like to reach value '3744', what field delimiter I should say?
$ps axu | grep jboss
jboss 2574 0.0 0.0 3744 1092 ? S Aug17 0:00 /bin/sh /usr/java/jboss/bin/run.sh -c example.com -b 0.0.0.0
cut -d' ' is not what I want, for it's only for one single space.
awk is not what I am looking for either, but how to do with 'cut'?
thanks.
Actually awk is exactly the tool you should be looking into:
ps axu | grep '[j]boss' | awk '{print $5}'
or you can ditch the grep altogether since awk knows about regular expressions:
ps axu | awk '/[j]boss/ {print $5}'
But if, for some bizarre reason, you really can't use awk, there are other simpler things you can do, like collapse all whitespace to a single space first:
ps axu | grep '[j]boss' | sed 's/\s\s*/ /g' | cut -d' ' -f5
That grep trick, by the way, is a neat way to only get the jboss processes and not the grep jboss one (ditto for the awk variant as well).
The grep process will have a literal grep [j]boss in its process command so will not be caught by the grep itself, which is looking for the character class [j] followed by boss.
This is a nifty way to avoid the | grep xyz | grep -v grep paradigm that some people use.
awk version is probably the best way to go, but you can also use cut if you firstly squeeze the repeats with tr:
ps axu | grep jbos[s] | tr -s ' ' | cut -d' ' -f5
# ^^^^^^^^^^^^ ^^^^^^^^^ ^^^^^^^^^^^^^
# | | |
# | | get 5th field
# | |
# | squeeze spaces
# |
# avoid grep itself to appear in the list
I like to use the tr -s command for this
ps aux | tr -s [:blank:] | cut -d' ' -f3
This squeezes all white spaces down to 1 space. This way telling cut to use a space as a delimiter is honored as expected.
I am going to nominate tr -s [:blank:] as the best answer.
Why do we want to use cut? It has the magic command that says "we want the third field and every field after it, omitting the first two fields"
cat log | tr -s [:blank:] |cut -d' ' -f 3-
I do not believe there is an equivalent command for awk or perl split where we do not know how many fields there will be, ie out put the 3rd field through field X.
Shorter/simpler solution: use cuts (cut on steroids I wrote)
ps axu | grep '[j]boss' | cuts 4
Note that cuts field indexes are zero-based so 5th field is specified as 4
http://arielf.github.io/cuts/
And even shorter (not using cut at all) is:
pgrep jboss
One way around this is to go:
$ps axu | grep jboss | sed 's/\s\+/ /g' | cut -d' ' -f3
to replace multiple consecutive spaces with a single one.
Personally, I tend to use awk for jobs like this. For example:
ps axu| grep jboss | grep -v grep | awk '{print $5}'
As an alternative, there is always perl:
ps aux | perl -lane 'print $F[3]'
Or, if you want to get all fields starting at field #3 (as stated in one of the answers above):
ps aux | perl -lane 'print #F[3 .. scalar #F]'
If you want to pick columns from a ps output, any reason to not use -o?
e.g.
ps ax -o pid,vsz
ps ax -o pid,cmd
Minimum column width allocated, no padding, only single space field separator.
ps ax --no-headers -o pid:1,vsz:1,cmd
3443 24600 -bash
8419 0 [xfsalloc]
8420 0 [xfs_mru_cache]
8602 489316 /usr/sbin/apache2 -k start
12821 497240 /usr/sbin/apache2 -k start
12824 497132 /usr/sbin/apache2 -k start
Pid and vsz given 10 char width, 1 space field separator.
ps ax --no-headers -o pid:10,vsz:10,cmd
3443 24600 -bash
8419 0 [xfsalloc]
8420 0 [xfs_mru_cache]
8602 489316 /usr/sbin/apache2 -k start
12821 497240 /usr/sbin/apache2 -k start
12824 497132 /usr/sbin/apache2 -k start
Used in a script:-
oldpid=12824
echo "PID: ${oldpid}"
echo "Command: $(ps -ho cmd ${oldpid})"
Another way if you must use cut command
ps axu | grep [j]boss |awk '$1=$1'|cut -d' ' -f5
In Solaris, replace awk with nawk or /usr/xpg4/bin/awk
I still like the way Perl handles fields with white space.
First field is $F[0].
$ ps axu | grep dbus | perl -lane 'print $F[4]'
My approach is to store the PID to a file in /tmp, and to find the right process using the -S option for ssh. That might be a misuse but works for me.
#!/bin/bash
TARGET_REDIS=${1:-redis.someserver.com}
PROXY="proxy.somewhere.com"
LOCAL_PORT=${2:-6379}
if [ "$1" == "stop" ] ; then
kill `cat /tmp/sshTunel${LOCAL_PORT}-pid`
exit
fi
set -x
ssh -f -i ~/.ssh/aws.pem centos#$PROXY -L $LOCAL_PORT:$TARGET_REDIS:6379 -N -S /tmp/sshTunel$LOCAL_PORT ## AWS DocService dev, DNS alias
# SSH_PID=$! ## Only works with &
SSH_PID=`ps aux | grep sshTunel${LOCAL_PORT} | grep -v grep | awk '{print $2}'`
echo $SSH_PID > /tmp/sshTunel${LOCAL_PORT}-pid
Better approach might be to query for the SSH_PID right before killing it, since the file might be stale and it would kill a wrong process.

linux shell scripting kiddie's question

an Unix shell script with only purpose - count the number of running processes of qmail (could be anything else). Easy thing, but there must be some bug in code:
#!/bin/bash
rows=`ps aux | grep qmail | wc -l`
echo $rows
Because
echo $rows
always shows greater number of rows (11) than if I just count rows in
ps aux | grep qmail
There are just 8 rows. Does it work this way on your system too?
Nowadays with linux, there is pgrep. If you have it on your system, you can skip grep -v grep
$ var=$(pgrep bash) # or `pgrep bash | wc -l`
$ echo $var
2110 2127 2144 2161 2178 2195 2212 2229
$ set -- $var; echo ${#}
8
also, if your ps command has -C option, another way
$ ps -C bash -o pid= | wc -l
if not, you can set a character class in your grep pattern
$ ps aux|grep [q]mail | wc -l
It appears that you're counting the grep process itself and the header line that ps normally prints before its output.
I'd suggest something more like:
qprocs=$(ps auxwww | grep -c "[q]mail")
... note that GNU grep has a "-c" switch to have it print a "count" of matches rather than the lines themselves. The trick with the regular expression here is to match qmail without matching the literal string that's on the grep command line. So we take any single character in the string and wrap it in square brackets such that it is a single character "class." The regexp: [q]mail matches the string qmail without matching the string [q]mail.
Note that even with this regex you may still find some false positive matches. If you really want to be more precise then you should supply a custom output format string to your ps command (see the man pages) or you should feed it through a pipemill or you should parse the output of the ps command based on fields (using awk or cut or a while read loop). (The -o option to ps is by far the easiest among these).
No, since I'm not running qmail. However, you will want to, at a bare minimum, exclude the process running your grep:
ps aux | grep qmail | grep -v grep
For debugging, you may want to do:
rows=`ps aux | grep qmail`
echo $rows >debug.input
od -xcb debug.input
(to see your input to the script in great detail) and then rewrite your script temporarily as:
#!/bin/bash
rows=`cat debug.input | wc -l`
echo $rows
That way, you can see the input and figure out what effect it's having on your code, even as you debug it.
A good debugger will eventually learn to only change one variable at a time. If your changing your code to get it working, that's the variable - don't let the input to your code change as well.
Use
$ /sbin/pidof qmail
A few ways...
ps -e | grep ' [q]mail' | wc -l
ps -C qmail -opid= | wc -l
pidof qmail | tr ' ' '\n' | wc -l
pgrep is on many Linux distributions, and I imagine available for other Unices.
[dan#khorium ~]$ whatis pgrep
pgrep (1) - look up or signal processes based on name and other attributes
[dan#khorium ~]$ pgrep mingetty
1920
1921
1922
1923
1924
In your case, pgrep qmail | wc -l should do the trick.

Resources