Avoid running unnecessary repetitive ps command

i have the following code:

                APIDS=$(echo $(ps -ef | awk -v gpid="${gpid}" '$2 == gpid || $3 == gpid {print $2,$3}') | sed 's~ ~|~g')
                AllProcs=$(ps -ef | awk -v allpids="${APIDS}" '$2 ~ allpids || $3 ~ allpids {print $0}' | sed '/^$/d')

it seems the above APIDS variable was created only to gather IPs. and then it is fed to the real command in the AllProcs variable.

can this be shortened into one command and also in an efficient way?

At some point in this bla | foo | kitchen | sink -, ahem, -command i lost the ability to picture a possible outcome. Could you please explain what this supposed to achieve? Or let it run on the system it was designed for and show some sample outcome.

One point i immediately saw was that ps -ef | awk ... | sed ... must be nonsense because either use awk or use sed and furthermore probably both are superfluous because the output of ps cat be tailored using the -o option. See the man page for details.

I hope this helps.

bakunin

Maybe something like this would work:

ps -ef | awk -v gpid="$gpid" '
{	line[NR] = $0
	pid[NR] = $2
	ppid[NR] = $3
}
$2 == gpid || $3 == gpid {
	PrintPid[$2]
	PrintPid[$3]
}
END {	for(i = 1; i <= NR; i++)
		if(pid in PrintPid || ppid in PrintPid)
			print line
}'

but, of course, ps -ef output may vary somewhat from operating system to operating system and you haven't told us what OS you're using. And, if you're using a Solaris/SunOS system, you'll need to change awk to /usr/xpg4/bin/awk or nawk .

1 Like

After sorting out some lome logical errors(e.g. the allpids matching), I guess you want a listing of the gpid process and its subprocesses. Try

ps -ef | awk -vGPID="$gpid" '$2 " " $3 ~ GPID'
1 Like

So it looks to me that you are trying to list all the processes with the PID or PPID of "${gpid}"

Consider this:

ps --ppid "${gpid}" -opid=

This will list the PIDs of all processes whose PPID is the gpid. If you have it,

pgrep -P${gpid} -d,

will do the same but give them in a comma-delimited list. So perhaps this?

ps -f --pid$(pgrep -P${gpid} -d,),${gpid}

If you don't have pgrep then you have to turn the output of my earlier ps command into a comma-delimited list and use that.

Caveat: GNU ps, GNU pgrep.

Andrew

1 Like

post#4 is unprecise (like post#1), for example will find pid 22 when searching for 2.
While the overall sense is not clear for me, this is certainly *not* intended.
Fix:

ps -ef | awk -vGPID="$gpid" '($2 == GPID || $3 == GPID)' 

Doesn't give this the same result as the code in post#3 ?
:confused:

2 Likes

No. It doesn't give the same result as the code in post #3. With slightly modified versions of these scripts:
./tester :

#!/bin/ksh
gpid=${1:-$$}
ps -ef | tee ps.out | awk -v gpid="$gpid" '
{	line[NR] = $0
	pid[NR] = $2
	ppid[NR] = $3
}
$2 == gpid || $3 == gpid {
	PrintPid[$2]
	PrintPid[$3]
}
END {	for(i = 1; i <= NR; i++)
		if(pid in PrintPid || ppid in PrintPid)
			print line
}'

Note that this captures the output from ps in ps.out which will be used as input for the other two scripts instead of rerunning ps . The above script produces the output:

  501   766   763   0  7Dec17 ttys003    0:01.40 -ksh
  501 27188   766   0 12:40PM ttys003    0:01.01 du /
  501 27189   766   0 12:40PM ttys003    0:00.01 /bin/ksh ./tester
    0 27190 27189   0 12:40PM ttys003    0:00.00 ps -ef
  501 27191 27189   0 12:40PM ttys003    0:00.00 tee ps.out
  501 27192 27189   0 12:40PM ttys003    0:00.00 awk -v gpid 27189

during a period where the command du / > du.out was running in the background while this script was running.

With this version of SkySmart's code modified to read from the ps.out produced by the above script:
./SkySmart :

#!/bin/ksh
gpid=${1:-$$}
APIDS=$(echo $(awk -v gpid="${gpid}" '$2 == gpid || $3 == gpid {print $2,$3}' ps.out) | sed 's~ ~|~g')
AllProcs=$(awk -v allpids="${APIDS}" '$2 ~ allpids || $3 ~ allpids {print $0}' ps.out | sed '/^$/d')
printf '%s\n' "$AllProcs"

and run with the operand 27189 , we get the output:

  501   766   763   0  7Dec17 ttys003    0:01.40 -ksh
  501 27188   766   0 12:40PM ttys003    0:01.01 du /
  501 27189   766   0 12:40PM ttys003    0:00.01 /bin/ksh ./tester
    0 27190 27189   0 12:40PM ttys003    0:00.00 ps -ef
  501 27191 27189   0 12:40PM ttys003    0:00.00 tee ps.out
  501 27192 27189   0 12:40PM ttys003    0:00.00 awk -v gpid 27189

which is identical to the output produced by the code in post #3. But with a similarly modified version of MadeInGermany's code:
./MadeInGermany :

#!/bin/ksh
gpid=${1:-$$}
awk -v GPID="$gpid" '($2 == GPID || $3 == GPID)' ps.out

and run with the operand 27189 , we only get the output:

  501 27189   766   0 12:40PM ttys003    0:00.01 /bin/ksh ./tester
    0 27190 27189   0 12:40PM ttys003    0:00.00 ps -ef
  501 27191 27189   0 12:40PM ttys003    0:00.00 tee ps.out
  501 27192 27189   0 12:40PM ttys003    0:00.00 awk -v gpid 27189

MadeInGermany's simpler code doesn't catch the parent, sibling, or grandchild processes of the process specified by $gpid . It only catches the process specified by $gpid and its children.

I do, however, agree that SkySmart's code works by accident when $gpid specifies a PID that isn't small enough to accidentally match several other unintended PIDs of unrelated running processes.

2 Likes