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

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)

Related

Shell Scripting array not printing proper values

I have this simple Shell Script where I am searching for ID and Port Number from the file and saving it in Array. However When I try to print them I am not getting expected results. I am looping the array to print the 1st and 2nd element and then increasing by two to print 3rd and 4th element. I also want to print them like each ID Port in separate line, like this:
ID Port
ID Port
My code is:
myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); for ((i=0;i<"${#myarr[#]}";i+=2)) ; do echo $i; printf "%s\n" "${myarr[$i]}" "${myarr[$i+1]}" ; done;
Even If I try to echo the whole array I only see the last element, whereas I could print each individual element without an issue.
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[#]}
45210
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[0]}
19
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[1]}
45210
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[2]}
20
$ myarr=($(less radius-req | grep C4-3A-BE-18-C1-2D -B75 | grep '2018-11\|Port' | grep -v User | grep Source -B1 | awk -F "Port:|id=" '{print $2}' )); echo ${myarr[3]}
45210
From the output you give, I suspect that the problem is due to carriage return characters in the radius-req file. My guess is the file is from Windows (or maybe a web download), which uses carriage return + linefeed as a line terminator. Unix uses just linefeed (aka newline) as a terminator, and unix programs will treat the carriage return as part of the content of the line. Net result: you get things like "19<CR>" and "45210<CR>" as array values, and when you print them it prints them all over top of each other.
If I'm right about the problem, it's pretty easy to fix. Just replace less radius-req (which you shouldn't use anyway, see William Pursell's comment) with tr -d '\r' <radius-req. The tr command does character replacements, -d means just delete instead of replacing, and \r is its notation for the carriage return character. Result: it deletes the carriage returns before they have a chance to mess things up.

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 }')

How to substract 1 from grep result

I am writing a bash command that sums the number of services running on specified ports. In my case 4092, 4903, 4904, 4905. Below is my command:
ps -ef | grep '4905\|4904\|4903\|4902' | wc -l
OUTPUT: 5
Here "\|" serves as OR operator. Now the result of this is 5, since it greps the command itself. How can I subtract 1 from the answer so that the output is 4.
Use:
ps -ef | grep '4905\|4904\|4903\|4902' | wc -l | awk '{print $0-1}'
You can remove the last line that contains the result itself before you print number of matches:
ps -ef | grep '4905\|4904\|4903\|4902' | head -n -1 | wc -l
you can save the wc and use awk to get the expected number
ps -ef|grep ...|awk 'END{print NR-1}'

BASH - GREP - invert much not working

I'm trying to find a number of open file descriptors by user "apache". I would like to exclude ls: /proc/PID/fd: No such file or directory but the GREP exclusing is not working:
# for pid in $(lsof -u apache | awk '{ print $2 }' | uniq); do ls -1 /proc/$pid/fd | grep -v "No"; done | wc -l
ls: /proc/PID/fd: No such file or directory
1944
Try |& grep -v "No such file or directory"
Unlike |, |& will also redirect the error output of ls
Try:
for pid in $(lsof -u apache | tail -n +2 | awk '{ print $2 }' | uniq); do ls -1 /proc/$pid/fd ; done | wc -l

shell command to find a process id and attach to it?

I want to attach to a running process using 'ddd', what I manually do is:
# ps -ax | grep PROCESS_NAME
Then I get a list and the pid, then I type:
# ddd PROCESS_NAME THE_PID
Is there is a way to type just one command directly?
Remark: When I type ps -ax | grep PROCESS_NAME, grep will match both the process and grep command line itself.
There is an easy way to get rid of the grep process:
ps -ax | grep PROCESS_NAME | grep -v ' grep '
(as long as the process you're trying to find doesn't include the string " grep ").
So something like this should work in a script (again, assuming there's only one copy running):
pid=$(ps -ax | grep $1 | grep -v ' grep ' | awk '{print $1}')
ddd $1 ${pid}
If you call your script dddproc, you can call it with:
dddproc myprogramname
Although I'd add some sanity checks such as detecting if there's zero or more than one process returned from ps and ensuring the user supplies an argument.
As separate commands:
% PID=`ps -ax | grep ${PROCESS_NAME} | grep -v grep | cut -d ' ' -f 1-2`
% ddd ${PROCESS_NAME} ${PID}
In one line:
% PID=`ps -ax | grep ${PROCESS_NAME} | grep -v grep | cut -d ' ' -f 1-2` && ddd ${PROCESS_NAME} ${PID}
ddd <process_name> `pgrep <process_name>`
you can use pggrep to find the process
You can use awk to both filter and get the column you want. The "exit" limits the ps results to the first hit.
function ddd_grep() {
ddd $(ps -ax | awk -v p="$1" '$4 == p { print $1; exit 0; }');
}
ddd_grep PROCESS_NAME
You may have to adjust the columns for your ps output. Also you can change the == to ~ for regex matching.
Do this way -
ddd PROCESS_NAME \`ps -ax | grep PROCESS_NAME | grep -v grep | awk '{print $1}'\`

Resources