Complicated grep commands not executing in shell script - bash

I am trying to execute a couple of complicated grep commands via a shells script that work fin in the terminal manually executed. I can't for the life of me figure out why this doesn't work.
The goal of the first grep is to get out any process id attached to the parent myPattern. The 2nd get the process id of the process myPattern
Currently my shell script
returns nothing for the 1st.
ignores the "grep -v 'grep'" part in the 2nd.
#!/bin/sh
ps -ef | grep "$(ps -ef | grep 'myPattern' | grep -v grep | awk '{print $2}')" | grep -v grep | grep -v myPattern | awk '{print $2}'
ps -ef | grep 'myPattern' | grep -v 'grep' | awk '{print $2}'
This works fine when run in the terminal manually. Any ideas where i have stuffed this up?

Your first command is vague. I don't think it would reliably do what you describe. It also does not guard against getting the id of the first grep call. The second one works for me. For the fists query it highly depends on the system you are using. It's easier to use pstree to show you the whole process tree under a pid. Like:
pstree -p 1782 | sed 's/-/\n/g' | sed -n -e 's/.*(\([0-9]\+\)).*/\1/p'
You need to limit pid to be a single value. If you have more values, then you have to loop through them. If you don't have pstree, then you can craft some loop around ps. Make note that even if you current commands worked, then thwy would catch only one level parent/child relationships. pstree does any level.
I also have to tell you that a process can escape original parent as a parent process by forking.
In any case without exact details what you are trying to achieve and why, and on what platform it is hard to give you a great answer. Also these utilities albeit present virtually everywhere are not as portable as one would wish.
One more note - /bin/sh is often not your current shell. On many linux systems user has a default shell of bash and /bin/sh is dash or some other shell variant. So if you see diffs with what you have in console and script, it can be difference in actual shell you are using.
Based on user feedback it would be much easier to have something like this in the java process launching script:
java <your params here> &
echo $! > /var/run/myprog.pid
Then the kill script would look like echo /var/run/myprog.pid | xargs kill. There are shorter commands but I think this is more portable. Give actual code if you want more specific.

Related

egrep gives me what I want, grep -E does not

I have read that egrep is deprecated in favour of grep -E so I'm looking back at my code and changing it where I find it.
But I see that the results are not always as expected.
With egrep, I get my list of running Oracle instances:
ps -ef|grep [p]mon|awk -F'ora_pmon_' '{print $NF}'|egrep -v 'ASM|^$'
halana
bila
halsasa
loana
However with grep -E, I get part of the awk in the results:
ps -ef|grep [p]mon|awk -F'ora_pmon_' '{print $NF}'|grep -Ev 'ASM|^$'
halana
bila
halsasa
{print $NF}
loana
Excluding 'print' obviously works but is it the right way to go about it?:
ps -ef|grep [p]mon|awk -F'ora_pmon_' '{print $NF}'|grep -Ev 'ASM\|^$|print'
halana
bila
halsasa
loana
Is this effect due to the fact that grep -E allows additional regular expression syntax?
Suggesting to simplify your line, eliminate all grep commands:
pgrep -af 'pmon'|awk -F'ora_pmon_' '!/ASM|^$/{print $NF}'
Fold first grep command into pgrep command.
Fold second grep command into awk scirpt !/ASM|^$/{print $NF}
About grep -E vs egrep
There is no difference whatsoever between these commands (they're even provided by the same executable on most operating systems); your old code was vulnerable to this bug too, and if you didn't see it, that's just a matter of being "lucky" in ps getting enough of the process list read before the shell gets to setting up the awk part of the pipeline.
Solving Your Problem
The right answer is already given by #DudiBoy, but the answer with the smallest possible change would be to make your awk (assuming it has GNU extensions and accepts regexes in the field separator specification) escape the string pmon the same way your first grep command does:
ps -ef|grep '[p]mon'|awk -F'ora_[p]mon_' '{print $NF}'|grep -Ev 'ASM|^$'

Using ps and awk to get pid, then killing it

I have written a very short script that gets pid of $1 then kills the process. I have a few questions / requests for improvement. (OSX)
#!/bin/bash
getpid=$(ps aux -O start | grep -i "$1" | grep -v grep | grep -v $0 | awk '{ if (NR==1) {print $2}}')
kill $getpid
For example:
$ ~/killpro.sh java
Which kills the most recent instance of java.
Or:
$ ~/killpro.sh chrome
To kill Google Chrome, obviously.
First, is there any practical way to get this strung together into a single line, using read -p perhaps, so that it can in turn be aliased and become something like:
$ killpro
$ Enter name: chrome
$
Not that it's significantly easier, in fact it's slightly more work, but it bypasses the need to type a path and shell extension which is desirable.
Second, is there anything fundamentally wrong with my initial approach / am I missing something obvious that negates the need for any this?
Any feedback is appreciated.
Thanks in advance, I'm (as you can tell) new to this.
My advice is to use pkill instead. From the manual page:
NAME
pgrep, pkill -- find or signal processes by name
Most scripts with grep | awk are a useless use of grep and should be refactored to use just Awk.
#!/bin/bash
# Maybe add a case for $# > 1 and quit with an error message
# Or maybe loop over arguments if there is more than one
case $# in 0) read -p "Process name? " proc;; *) proc=$1;; esac
# Maybe your ps aux doesn't have the command in $11 -- adapt
kill $(ps aux -O start |
awk -v name="$proc" 'NR>1 && tolower($11) ~ tolower(name) {print $2}')
Your comments indicate you seek to kill the "latest" process (by which metric?) but your code, and this code, attempts to kill all the instances. If you want the most recently started process, the PID is not a good indicator; you should look at process start times etc. The output of ps is heavily system-dependent so you should probably post a separate question with more details about your OS if you need help figuring that out.
This particular problem regularly gets beaten to death several times a month here, so you should probably look at other implementations for inspiration. My recommendation would be "don't do that" but since you already did, I suppose it makes sense to point out the flaws and attempt to solidify the code. But if you don't have a compelling reason why you cannot install pkill, you should probably just use that (and if you do, using a properly debugged and tested script is way better than writing your own from scratch).
You could just use awk alone with getline to call out to ps and get the data you want:
awk -vv_kp="bash" 'BEGIN{ cmd="ps -axu -O T | grep "v_kp" |head -1"; cmd | getline var; close(cmd); split(var,var2," ");print var2[2];}'
or less awk, more shell:
awk -vv_kp="bash" 'BEGIN{ cmd="ps -axu -O T | grep "v_kp" |head -1|cut -d\" \" -f2"; cmd | getline var; close(cmd); print var;}'

How to choose the first result on shell script

I want to look for a specific process and then kill it (in a script).
I'm doing ps -fu user | grep matching_string but this is returning me two rows: one for the expected pid and another for the pid of the grep.
If the result were two columns, I would use awk to pick the first one. But I don't know how to pick the first result when they are returned as row.
How about pkill?
pkill -U user-id process-name
You can use this trick:
ps -fu user | grep matching_strin[g]
This way, the grep match won't appear.
How does it work? (see Find and kill a process in one line using bash and regex for more detail).
With ps -fu user | grep matching_string it lists all the processes having grep matching_string, so that includes the grep itself.
Doing ps -fu user | grep matching_strin[g] you add a regular expression that makes grep skip the grep itself. Why? Because the process name is grep matching_strin[g] and does not match the literal matching_string.

How to get the PID of a process by giving the process name in Mac OS X ?

I am writing a script to monitor the CPU and MEM of any given process. For that i need to send in the name of the process to be monitored as a commandline argument. For example.
./monitorscript <pname>
I need to get the pid of the process in the script so that i can use a ps -p <pid> inside.
How do i get the pid of a process given its process name?
I understand that there might be multiple processes in the same name. I just want to get the first process out of that list.
The answer above was mostly correct, just needed some tweaking for the different parameters in Mac OSX.
ps -A | grep [f]irefox | awk '{print $1}'
You can use the pgrep command like in the following example
$ pgrep Keychain\ Access
44186
You can install pidof with Homebrew:
brew install pidof
pidof <process_name>
This solution matches the process name more strictly:
ps -Ac -o pid,comm | awk '/^ *[0-9]+ Dropbox$/ {print $1}'
This solution has the following advantages:
it ignores command line arguments like tail -f ~/Dropbox
it ignores processes inside a directory like ~/Dropbox/foo.sh
it ignores processes with names like ~/DropboxUID.sh
This is the shortest command I could find that does the job:
ps -ax | awk '/[t]he_app_name/{print $1}'
Putting brackets around the first letter stops awk from finding the awk process itself.
Try this one:
echo "$(ps -ceo pid=,comm= | awk '/firefox/ { print $1; exit }')"
The ps command produces output like this, with the PID in the first column and the executable name (only) in the second column:
bookworm% ps -ceo pid=,comm=
1 launchd
10 kextd
11 UserEventAgent
12 mDNSResponder
13 opendirectoryd
14 notifyd
15 configd
...which awk processes, printing the first column (pid) and exiting after the first match.
You can try this
pid=$(ps -o pid=,comm= | grep -m1 $procname | cut -d' ' -f1)
ps -o ppid=$(ps -ax | grep nameOfProcess | awk '{print $1}')
Prints out the changing process pid and then the parent PID. You can then kill the parent, or you can use that parentPID in the following command to get the name of the parent process:
ps -p parentPID -o comm=
For me the parent was 'login' :\
Why don't you run TOP and use the options to sort by other metrics, other than PID? Like, highest used PID from the CPU/MEM?
top -o cpu <---sorts all processes by CPU Usage

Shell scripting obtain command PID

In a shell script lets say i have run a command like this
for i in `ps -ax|grep "myproj"`
do
echo $i
done
Here, the grep command would be executed as a separate process. Then how do i get its PID in the shell script ?
I'm going out on a limb here, and understand this looks more like a comment.
Why do you need the PID of the grep command?
In your comment you say you want to compare it in the loop against something. I would suppose that it is your issue that that the loop will (sometimes) not only include myproj but also an item about your grep command? If so, try the following:
for i in `ps -ax | grep -v grep | grep "myproj"`
do
echo $i
done
The -v switch basically inverts the pattern, so grep -v grep (or grep -v "grep", which maybe looks a bit less awkward) will include only lines that do not include the string "grep" (see man grep).
Note that this maybe overly vague for some cases, for example if the pattern you actually look for also contains the string "grep". For example, the following might not work as you'd expect: ps -ax | grep -v grep | grep mygrepling
However, in your particular case, where you only look for "myproj" it will do.
Or you could simply use
for i in `ps -ax | grep "my[p]roj"`
do
echo $i
done
That way there is no need to know the PID of the grep command, because it simply never shows up as a loop iteration.
When you run a process in background, you can get its PID in $!
$ ps aux | grep dddddd & echo $!
[1] 27948
27948
ic 27948 0.0 0.0 3932 760 pts/3 R 08:49 0:00 grep dddddd
When in foreground --- the process does not exist anymore at the point you want to find its PID. When you are in the loop, the for statement is already executed and grep is already exited, so you can not find its PID anymore.

Resources