Get details of all tcp listening processes - shell

#! /bin/bash
a=`netstat -plant | grep -i listen`
#to get ip and port
b=`echo $a | awk {'print $4}'`
#to get the process id
c=`echo $a | awk {'print $7}' | awk -F '/' {'print $1'}`
set -- $c
#to get the details of process
g=`ps aux | grep $1`
m=`echo $g | awk {'print $2}'`
n=`echo $g | awk {'print $9}'`
o=`echo $g | awk {'print $11}'`
echo The process with PID $m invoked by command "$o", is listening at IP and Port : $b . The process has been running since $n
I was trying to make a script to display the details like PID, IP, port, running since, and the command of all tcp listening processes in a simple language. The script I made gives the details of only 1 process

You only need to change the assignment to a with a while read construct:
netstat -plant | grep -i listen | while read a; do
#to get ip and port
b=`echo $a | awk {'print $4}'`
#to get the process id
c=`echo $a | awk {'print $7}' | awk -F '/' {'print $1'}`
set -- $c
#to get the details of process
g=`ps aux | grep $1`
m=`echo $g | awk {'print $2}'`
n=`echo $g | awk {'print $9}'`
o=`echo $g | awk {'print $11}'`
echo The process with PID $m invoked by command "$o", is listening at IP and Port : $b . The process has been running since $n
done
This construct will read output from the grep into a variable one line at a time.

Related

How to grep first match and second match(ignore first match) with awk or sed or grep?

> root# ps -ef | grep [j]ava | awk '{print $2,$9}'
> 45134 -Dapex=APEC
> 45135 -Dapex=JAAA
> 45136 -Dapex=APEC
I need to put the first APEC of first as First PID, third line of APEC and Second PID and last one as Third PID.
I've tried awk but no expected result.
> First_PID =ps -ef | grep [j]ava | awk '{print $2,$9}'|awk '{if ($0 == "[^0-9]" || $1 == "APEC:") {print $0; exit;}}'
Expected result should look like this.
> First_PID=45134
> Second_PID=45136
> Third_PID=45135
With your shown samples and attempts please try following awk code. Written and tested in GNU awk.
ps -ef | grep [j]ava |
awk '
{
val=$2 OFS $9
match(val,/([0-9]+) -Dapex=APEC ([0-9]+) -Dapex=JAAA\s([0-9]+)/,arr)
print "First_PID="arr[1],"Second_PID=",arr[3],"Third_PID=",arr[2]
}
'
How about this:
$ input=("1 APEC" "2 JAAA" "3 APEC")
$ printf '%s\n' "${input[#]}" | grep APEC | sed -n '2p'
3 APEC
Explanation:
input=(...) - input data in an array, for testing
printf '%s\n' "${input[#]}" - print input array, one element per line
grep APEC - keep lines containing APEC only
sed -n - run sed without automatic print
sed -n '2p' - print only the second line
If you just want the APECs first...
ps -ef |
awk '/java[ ].* -Dapex=APEC/{print $2" "$9; next; }
/java[ ]/{non[NR]=$2" "$9}
END{ for (rec in non) print non[rec] }'
If possible, use an array instead of those ordinally named vars.
mapfile -t pids < <( ps -ef | awk '/java[ ].* -Dapex=APEC/{print $2; next; }
/java[ ]/{non[NR]=$2} END{ for (rec in non) print non[rec] }' )
After read from everyone idea,I end up with the very simple solution.
FIRST_PID=$(ps -ef | grep APEC | grep -v grep | awk '{print $2}'| sed -n '1p')
SECOND_PID=$(ps -ef | grep APEC | grep -v grep | awk '{print $2}'| sed -n '2p')
JAWS_PID=$(ps -ef | grep JAAA | grep -v grep | awk '{print $2}')

how to retrieve open file handle count for a pid via shell script

I am trying to retreive open file handle count for a particular PID in a variable via shell script and displaying the same.It is not showing the correct count. Can someone please advise?
pid=$(ps -ef | grep 'instance="AC"' | grep -v grep | awk '{print $2}') f_count=$(ls /proc/$'{pid}' | wc -l)
Expected output:
=============
When executed in command line , it shows
ps -ef | grep 'service_instance="AC"' | grep -v grep | awk '{print $2}'
25939
ls /proc/25939/fd | wc -l
98
Actual Output:
f_count= 0
Appreciate your help, thanks
Suggesting to replace:
pid=$(ps -ef | grep 'instance="AC"' | grep -v grep | awk '{print $2}')
With:
pid=$(pgrep -f 'instance="AC"')
Notice that pid takes the first matched process.
If there are more than one matched process pgrep returns multiple lines.
Suggesting to replace:
f_count=$(ls /proc/$'{pid}' | wc -l)
with
f_count=$(ls /proc/${pid}/fd | wc -l)
Or all together in one line
f_count=$(ls /proc/$(pgrep -f 'instance="AC"')/fd | wc -l)

One-liner to retrieve path from netstat port

I'm looking to create a one liner that, given a port number (2550) uses the returned value from netstat would allow me to then run the resulting output against ps -ef to return the path of the process in question. I have:
ps -ef | grep $(netstat -tonp | grep 2550 | awk '{split($7,a,"/"); print a[1]}')
and whilst I know
netstat -tonp | grep 2550 | awk '{split($7,a,"/"); print a[1]}'
returns the expected resulted, the subsequent grep tells me that there is no such file or directory (but, if I do the ps -ef | grep **) it works just fine... I'm obviously missing something... well, obvious, but I can't see what?
try something like (it takes the first PID/port corresponding, not all):
Port=2550;ps -f --pid $( netstat -tonp | awk -F '[ \t/]+' -v Port=$Port '$0 ~ "([0-9]+[.:]){4}" Port { PID= $7;exit}; END { print PID+0 }' ) | sed 's/^\([^ \t]*[ \t]*\)\{7\}//'
the last sed is assuming a ps reply like this (space are important):
usertest 4408 4397 0 09:43 pts/6 00:00:00 ssh -p 22 -X -l usertest 198.198.131.136
for every PID and with no ending sed:
Port=2550; ps -ef | awk -v PIDs="$( netstat -tonp | awk -F '[ \t/]+' -v Port=${Port} '$0 ~ (":" Port) { print $7}' )" 'BEGIN{ split( PIDs, aTemp, /\n/); for( PID in aTemp) aPID[ aTemp[PID] ] }; $2 in aPID { sub( /^([^ \t]*[ \t]*){7}/, ""); print}'
This will give you the pids:
<sudo> netstat -tulpen | awk '$4 ~ /:2550$/{sub("/.*","",$NF);print $NF}'
You can use xargs to pass the pid to ps:
netstat -tulpen | awk '$4 ~ /:2550$/{sub("/.*","",$NF);print $NF}' | xargs -P 1 ps -o pid,cmd -p

Running Shell Script having multiple programs dynamically in parallel

I have a shell script which captures the Process ID, CPU and Memory of the JVM every nth second and writes the output to a file. Below is my code:
JVM="aaa001_bcdefx01"
systime=$(date +"%m-%d-%y-%T")
for i in {1..10}
do
PID=`ps -auxwww | grep "jdk" | grep $JVM | grep -v grep | cut -c -30 | awk '{print $2}'`
MEM=`ps -auxwww | grep "jdk" | grep $JVM | grep -v grep | cut -c -30 | awk '{print $4 }'`
CPU=`ps -auxwww | grep "jdk" | grep $JVM | grep -v grep | cut -c -30 | awk '{print $3 }'`
printf '%-5s %-20s %-20s %-20s %-20s \n' "$systime $JVM $PID $CPU $MEM " >> $LOGFILE
sleep 5
done
This run perfectly fine when i have only one JVM in that server. How can i execute the same script in parallel and fetch the details if i have multiple JVM for a server.
I looked for some solutions and found & to be used in the script but couldn't understand how this can be implemented to my above script. Let's say I have 5 JVMs. How can i run the script and fetch the stats in parallel for all the below JVMs in parallel. Kindly guide. Any help would be appreciated.
JVM="aaa001_bcdefx01"
JVM="aaa002_bcdefx01"
JVM="aaa003_bcdefx01"
JVM="aaa004_bcdefx01"
JVM="aaa005_bcdefx01"
GNU Parallel is made for this kind of stuff
doit() {
JVM="$1"
systime=$(date +"%m-%d-%y-%T")
for i in {1..10}
do
PID=`ps -auxwww | grep "jdk" | grep $JVM | grep -v grep | cut -c -30 | awk '{print $2}'`
MEM=`ps -auxwww | grep "jdk" | grep $JVM | grep -v grep | cut -c -30 | awk '{print $4 }'`
CPU=`ps -auxwww | grep "jdk" | grep $JVM | grep -v grep | cut -c -30 | awk '{print $3 }'`
printf '%-5s %-20s %-20s %-20s %-20s \n' "$systime $JVM $PID $CPU $MEM "
sleep 5
done
}
export -f doit
parallel -j0 --linebuffer --tag doit ::: aaa00{1..5}_bcdefx01 >> $LOGFILE
The function is basically your code. The change is that it takes the JVM as argument and it prints to stdout (standard output). GNU Parallel calls the function with the arguments aaa00N_bcdefx01 where N = 1..5, and saves the output to $LOGFILE. It uses --linebuffer to pass the output as soon as there is a full line, and thus guarantees that you will not get half-a-line from one process mixed with a line from another process. --tag prepends the line with the JVM.
How about using subshell?
Each JVM shell script should go inside '(' and ')'. Put '&' at the end so that it executes in the background.
An example is given here.
#!/bin/bash
echo > testfile.txt
echo "execute subshell 1"
(
#JVM 1 should go here
sleep 10
echo "subshell 1" >> testfile
)&
echo "execute subshell 2"
(
#JVM 2 should go here
sleep 10
echo "subshell 2" >> testfile
)&
echo "execute subshell 3"
(
#JVM 3 should go here
sleep 10
echo "subhsell 3" >> testfile
)&
Here each subshell writes data to testfile.txt after waiting for 10 seconds.

How to reference multiple string values in array in Shell script

I am trying to store multiple string in for loop but it giving me unwanted answer.
My code is :
#!/bin/bash
declare -a arr=("ps -ef | grep icsmpgum | grep $USER | grep -v grep | awk '{print $9,$8}' | awk '{print $1}'")
for i in "${arr[#]}"
do
echo "$i"
done
The output of
ps -ef | grep icsmpgum | grep $USER | grep -v grep | awk '{print $9,$8}' | awk '{print $1}'
is :
icsmpgum
ABC
DEF
I want to refer to these 3 string values in for loop but after applying for loop as mention above it giving me output as :
Output :
ps -ef | grep icsmpgum | grep tsaprm1 | grep -v grep | awk '{print ,}' | awk '{print }'
How should I store these string values in variables ?
You need to use a command substitution, rather than quoting the command:
arr=( $(ps -ef | grep icsmpgum | grep $USER | grep -v grep | awk '{print $9,$8}' | awk '{print $1}') )
I suspect that this will work but there's a lot of further tidying up to be done; all the filtering that you want to do is possible in one call to awk:
arr=( $(ps -ef | awk -v user="$USER" '!/awk/ && /icsmpgum/ && $0 ~ user { print $9 }') )
As mentioned in the comments, there are potential risks to building an array like this (e.g. glob characters such as * would be expanded and you would end up with extra values in the array). A safer option would be to use a process substitution:
read -ra arr < <(ps -ef | awk -v user="$USER" '!/awk/ && /icsmpgum/ && $0 ~ user { print $9 }')

Resources