BASH commands: pkill/pgrep - bash

I'm struggling with understanding the difference between using pgrep, as opposed to using ps | grep.
Apart from the fact that pgrep will only list the PID, what is the difference?
When I run an instance of kwrite in the background of my terminal, as well as opening one up using the GUI, why is the output given by ps | grep kwrite only one PID, when two instances of kwrite are running?
On a slightly different note, why would using pkill to kill a crashed instance of kwrite not be a good way of killing a process? The only explanation that I could come up with, is that it would kill all processes with the string "kwrite" in them, and that may not be only the instance of kwrite I wanted to kill.
Thank you for your help.

ps | grep will fork 2 processes, pgrep only one.
ps | grep whatever may also list grep whatever depending when ps exits, pgrep whatever will not.
ps will need additonal command-line switches to show up both kwrite processes. (see: man ps and try ps -ef next time)
By default, ps selects all processes with the same effective user ID (euid=EUID) as the current user and associated with the same terminal as the invoker.
Try running a handfull kwrite instances, preferably with important and unsaved data to find out, why killing the crashed one using pkill might not be the most clever idea.

Related

ROS/Linux: What exactly does '&' in the linux terminal?

I am working with ROS. And for starting ros-packages you need to have the ROS Master run in the background. Now when I want to start the ROS-package rviz, instead of opening two terminals:
Terminal1:
$ roscore
Terminal2:
$ rviz
I can do the follwing in one Terminal:
$ roscore& rviz
But what exactly is happening here? Because when I end that terminal with Str+C it only closes rivz, but roscore is kept running in the background? Why and how can I close it?
in case using single & the left side will run in the background, while the right side will run normally in the terminal.
Now to close the first process you need to find PID (Process ID) and do the termination command, so first of all you need to find PID and you can use pgrep (in your case PROCESS_NAME can be roscore):
pgrep -f PROCESS_NAME
Now to kill the process you can easily do:
kill -9 PID_HERE
Or you can do it by single command:
pgrep -f PROCESS_NAME | xargs kill -9

starting a new process group from bash script

I basically want to run a script (which calls more scripts) in a new process group so that I can send signal to all the processes called by the script.
In Linux, I found out setsid helps me in doing that, but this is not available on FreeBSD.
Syntax for setsid (provided by util-linux-ng).
setsid /path/to/myscript
I, however learnt that session and process group are not the same. But starting a new session also solves my problem.
Sessions and groups are not the same thing. Let's make things clean:
A session consists of one or more process groups, and can have a controlling terminal. When the session has a controlling terminal, the session has, at any moment, exactly one foreground process group and one or more background process groups. In such a scenario, all terminal-generated signals and input is seen by every process in the foreground process group.
Also, when a session has a controlling terminal, the shell process is usually the session leader, dictating which process group is the foreground process group (implicitly making the other groups background process groups). Processes in a group are usually put there by a linear pipeline. For example, ls -l | grep a | sort will typically create a new process group where ls, grep and sort live.
Shells that support job control (which also requires support by the kernel and the terminal driver), as in the case of bash, create a new process group for each command invoked -- and if you invoke it to run in the background (with the & notation), that process group is not given the control of the terminal, and the shell makes it a background process group (and the foreground process group remains the shell).
So, as you can see, you almost certainly don't want to create a session in this case. A typical situation where you'd want to create a session is if you were daemonizing a process, but other than that, there is usually not much use in creating a new session.
You can run the script as a background job, as I mentioned, this will create a new process group. Since fork() inherits the process group ID, every process executed by the script will be in the same group. For example, consider this simple script:
#!/bin/bash
ps -o pid,ppid,pgid,comm | grep ".*"
This prints something like:
PID PPID PGID COMMAND
11888 11885 11888 bash
12343 11888 12343 execute.sh
12344 12343 12343 ps
12345 12343 12343 grep
As you can see, execute.sh, ps and grep are all on the same process group (the value in PGID).
So all you want is:
/path/to/myscript &
Then you can check the process group ID of myscript with ps -o pid,ppid,pgid,comm | grep myscript. To send a signal to the group, send it to the group leader (PGID is the PID of the leader of the group). A signal sent to a group is delivered to every process in that group.
Using FreeBSD you may try using the script command that will internally execute the setsid command.
stty -echo -onlcr # avoid added \r in output
script -q /dev/null /path/to/myscript
stty echo onlcr
# sync # ... if terminal prompt does not return
This is not exactly answer, but is an alternative approach based on names.
You can have a common part of name for all process. For example we have my_proc_group_29387172 part for all the following processes:
-rwxrwxr-x. my_proc_group_29387172_microservice_1
-rwxrwxr-x. my_proc_group_29387172_microservice_2
-rwxrwxr-x. my_proc_group_29387172_data_dumper
Spawn all of them (and as much as you want):
ADDR=1 ./my_proc_group_29387172_microservice_1
ADDR=2 ./my_proc_group_29387172_microservice_1
ADDR=3 ./my_proc_group_29387172_microservice_2
./my_proc_group_29387172_data_dumper
When you want to kill all processes you can use pkill command (pattern kill) or killall with --regexp parameter:
pkill my_proc_group_29387172
Benefit :) - you can start as many process as you want at any time (or any day) from any script.
Drawback :( - you can kill innocent processes if they has common part of name with your pattern.

How to display list of processes sorted in reverse order for a bash, tsch, ksh shell in Unix

Was wondering if someone could help me with this... I want to display a list of running processes sorted in reverse order. The reverse order is to be based on process identification value - PID.
I was also wondering does it matter for the processes to be displayed in a certain shell? do I have to include something specific in the line of code or merely just change shells. I want to do this for both tsch and bash.
I have looked up the commands but I am not sure how to bring it together. See below:
ps = is the command that shows information about processes running in memory
-p = by process ID
r = running processes
sorting method?
Not sure how to bring it together.
Thanks for the help
This will do it:
ps aux | sort -k2 -rn
The ps command varies depending on OS. I can confirm the above will work in Linux and FreeBSD.
ps has it's own sort on linux, This is how I use it:
ps -eo pid,user,rss,vsz,pmem,comm,lstart --sort rss
In your case
ps aux --sort pid
In bash the following command will do it:
~$ ps aux --sort -pid | less
Normal (descending) order is achieved by specifying --sort pid or --sort +pid. The latter doesn't make much sense though.

is there any way to know the pid of a launched program?

if I launch a bash script as a child, I can pass its own pid to the parent by using $$.
Is there any way to find the pid of a program that I launch from a script in background
like:
ping x.x.x.x &
what's the pid of that ping ?
(I just hope I expressed my self correctly ... my English is not the best)
PS. I'm looking for a simple and clean solution, I can imagine something like:
ping -t10000 -W10 x.x.x.x &
then
ps ax | grep 'ping -t10000 -W10 x.x.x.x'$
but is too complicated, also even that I used switches to personalize it is not clean, it may catch another processes in the system
The variable $! has the PID of the last background process you started.
Use this: $! right after executing the command whose PID you want. It means, though that you need to use an ampersand (&) after the command, to start it in background. E.g.:
my_command & CMDPID=$!
echo "$CMDPID"

How can I find out what a command is executing in Terminal on MacOs

After I run a shell script (which call a bunch a other scripts depend on conditions. which is too complicated to understand), I can execute a command 'gdbclient' at my MacOS terminal.
But when I do 'which gdbclient' and 'alias gdbclient', it shows nothing.
Is there anyway for me to find out what 'gdbclient' is actually doing?
You can open up another terminal window and type: ps
That will list all the running processes.
If your script is running as a different user than the current one, you can use ps -ef to list all running processes.
If you know the PID of the process that ran your script, you can find all child processes via parent PID using ps -f | grep [pid]
You can use the Activity Monitor to check things out pretty thoroughly. To get the right privileges to see everything going on you can do:
sudo open /Applications/Utilities/Activity\ Monitor.app/
Dtrace can give you some helpful information: dtrace
to find process 'gdbclient':
ps aux | grep gdbclient
That wont tell you what it's "doing" but that it's running

Resources