How to get the two lines(head+filtered content) as output with a simple command? - bash

I want to get the head as in my output.
ps lax |head -n 1
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
And the filtered line:
ps lax |grep openbox |grep -v grep
0 1000 1608 1513 20 0 206408 20580 SyS_po S ? 0:00 openbox --config-file /home/debian9/.config/openbox/lxde-rc.xml
What i expect to get is as below two lines:
F UID PID PPID PRI NI VSZ RSS WCHAN STAT TTY TIME COMMAND
0 1000 1608 1513 20 0 206408 20580 SyS_po S ? 0:00 openbox --config-file /home/debian9/.config/openbox/lxde-rc.xml
How to get the two lines(head+filtered content) as output with a simple command?

For compound conditions you use awk, not grep:
ps lax | awk 'NR==1 || /[o]penbox/'
Note the idiomatic use of [o] in #Cyrus and my answers so that the regexp doesn't match on this command itself so you don't need to explicitly remove this command name from with regexp.

ps lax | grep -e '^F' -e '[o]penbox'
or
ps lax | grep '^F\|[o]penbox'

Ed's answer using awk plus the NR==1 condition is the best solution.
For completeness, let me show the use of tee and processs substitution with >(command).
For instance: to display current processes (with ps) other than bash while retaining the ps header line, use tee in the following way:
$ ps | tee >(sed -n 1p) >(sed 1d | grep -v bash) > /dev/null
PID PPID PGID WINPID TTY UID STIME COMMAND
5782 2514 3792 1940 cons2 1415878 12:21:38 /usr/bin/ps
9998 2 9708 9708 ? 1415878 12:38:41 /usr/bin/ssh-agent
$
Here tee redirects the output to two processes:
one to display the first line (first sed -n 1p),
then other that filters the first line (the other sed 1d) and does an additional filtering with grep.
Finally, to prevent tee from dumping the original ps output, stdout is redirected to /dev/null

Related

How to take a single line of input from a long running command, then kill it?

Is there a way to take one line of input from a stream, pass it on as an argument and kill the stream?
In pseudo-bash code:
tail -f stream | filter | take-one-and-kill-tail | xargs use-value
Edit: actual script so far is:
i3-msg -t subscribe -m '["window"]'| stdbuf -o0 -e0 jq -r 'select(.change == "new") | "\(.container.window)\n"' | head -0
and it has following (undesirable) behaviour:
$ i3-msg -t subscribe -m '["window"]'| stdbuf -oL -eL jq -r 'select(.change == "new") | "\(.container.window)\n\n"' | head -1
# first event happens, window id is printed
79691787
# second event happens, head -1 quits
$
You could run the command in subshell and kill that shell.
In this example I'm killing the stream after the first info message:
#!/bin/bash
( sudo stdbuf -oL tail -f /var/log/syslog | stdbuf -oL grep -m1 info ; kill $$ )
Note: ( pipeline ) will run the pipeline in a subshell. $$ contains the pid of the current shell. (Which is the subshell in the above example)
In the above example grep -m1 is ensuring that only one line of ouput is read/written before killing the pipe.
If your filter program does not support such an option like -m1, you could pipe to awk and exit awk after the first line of input. The remaining concept stays the same:
( sudo stdbuf -oL tail -f /var/log/syslog \
| stdbuf -oL grep info \
| awk '{print;exit}' ; kill $$)

Difference using ps|wc -l with or without bash variable

Using bash, I would like to understand the different outputs between :
ps |wc -l
4
and
n=$(ps|wc -l)
echo $n
5
I guess the $(ps|wc -l) instruction is creating an additional subprocess, but I don't really understand why it is addded to the ps count
You said it: $( ) creates a subprocess. Because the command ps without options precisely lists all subprocesses of the current shell, you get one more line. I checked this by replacing wc with tee:
$ ps | tee four
PID TTY TIME CMD
XXXXXXX pts/5 00:00:00 bash
YYYYYYY pts/5 00:00:00 ps
ZZZZZZZ pts/5 00:00:00 tee
$ : $(ps -H | tee five)
$ cat five
PID TTY TIME CMD
XXXXXXX pts/5 00:00:00 bash
YYYYYYY pts/5 00:00:00 bash
ZZZZZZZ pts/5 00:00:00 ps
ΩΩΩΩΩΩΩ pts/5 00:00:00 tee
I also passed -H to ps so that it evidences the process tree.

how to extract the PID of a process by command line

I want to get the PID of a process namely "cron" by command line.
I tried the following script.
ps ax|grep 'cron'
but I am getting a part of a table,
1427 ? Ss 0:00 /usr/sbin/cron -f
24160 pts/5 S+ 0:00 grep --color=auto cron
How I extract the pid from this ?
The pgrep utility will return the process IDs for the currently running processes matching its argument:
$ pgrep cron
228
It may also be used to "grep for" things on the command line:
$ pgrep -f uerfale
69749
69752
$ pgrep -l -f uerfale
69749 slogin uerfale
69752 slogin: /home/kk/.ssh/sockets/uerfale-9022-kk.sock [mux] m
To kill a process by name, use pkill. It works in the same way as pgrep but will send a signal to the matched processes instead of outputting a process ID.
Just use pidof, rather to use other commands and apply post-processing actions on them.
$ pidof cron
22434
To make the command return only one PID pertaining to to the process, use the -s flag
-s
Single shot - this instructs the program to only return one pid.
Like this, for example:
ps -ef|grep 'cron'|grep -v grep|awk '{print $2}'
You can try this;
ps -o pid,sess,cmd afx | egrep "( |/)cron( -f)?$"
or
pstree -pas <cronPID>

bash: differing newline count when assigning result to variable [duplicate]

This question already has answers here:
Check number of running scripts using ps
(4 answers)
Closed 6 years ago.
let's say I want to see how many copies of a program are already running. I could do something like this:
ps ax | grep -c "$0"
that command by itself produces the expected result. BUT if I attempt to assign the output to a variable, it gets incremented by one! No matter how I try it:
var=$(ps ax | grep "$0" | sed -n '$=')
var=`ps ax | grep -c "$0"`
can someone please show me the right way to capture the correct output?
it would also be great to know why this is happening..
UPDATE
after the first response from #fedorqui I realize I wasn't clear enough. let me elaborate:
I am running all three commands above in the same bash script. When I run the first one, it prints out the number 2: the program itself and the grep process with that program as an argument. when I run those same commands within variable assignments, the number 3 is stored.
please note that I am using two different methods of counting lines, grep and sed. in both cases they return 3 instead of the correct answer, 2.
here is a consolidated example to try in a test.sh file:
echo -n "without assignment: "
ps ax | grep -c "$0"
var=$(ps ax | grep "$0" | sed -n '$=')
echo "using sed method: $var"
var=`ps ax | grep -c "$0"`
echo "using grep method: $var"
the results on my debian box:
without assignment: 2
using sed method: 3
using grep method: 3
the questions again: why is this happening, and how to prevent or work around?
Quoting Siegex:
Because the grep process itself is being returned by ps.
You can either of these:
"trick" grep to not match itself by surrounding one of the search
characters in a character class [ ] which doesn't change the
functionality:
Or, in this case,
Pipe to grep -v grep, so that the process doesn't match:
var=$(ps ax | grep -v grep | grep "$0")
See an example. Here we have a process sleep:
$ sleep 20 &
[1] 5602
If we check for it in the output of ps it appears twice!
$ ps -ef| grep sleep
me 5602 5433 0 09:49 pts/2 00:00:00 sleep 20
me 5607 5433 0 09:49 pts/2 00:00:00 grep --colour=auto sleep
So we can either use a character class:
$ ps -ef| grep [s]leep
me 5602 5433 0 09:49 pts/2 00:00:00 sleep 20
Or grep out the grep process:
$ ps -ef| grep sleep | grep -v grep
me 5602 5433 0 09:49 pts/2 00:00:00 sleep 20
Command substitution itself runs in a subshell so thats one bash process
your search for bash ($0) i.e. grep -c bash also ends up in the process table at that time so thats another process (grep) containing string bash. Note that, this might not show up in the process table at the time of running, depending on how busy your system is.
And you have two (or whatever) actual bash processes (sessions) running presumably are the rest
You can use a Regex trick to get rid of the false positive i.e. grep one from count:
ps ax | grep -c "[b]ash"
It would still count the subshell while doing command substitution:
var=$(ps ax | grep -c "[b]ash")
So you need to manually remove one from this count.
Example:
$ var=$(ps ax | grep -c "bash")
$ echo $var
4
$ var=$(ps ax | grep -c "[b]ash")
$ echo $var
3
Your command counts the grep command line too.
ps ax | grep -v grep | grep -c "$0"
should omit the grep from the count

Get the username and the process ID of a process in bash

I am writing a bash script where I need to find out the userID of a process. For an example let the process be bash itself.
I tried ps aux | grep ba[s]h but the following was returned:
1000 2745 0.0 0.1 28360 5440 pts/1 Ss 10:11 0:01 bash
I see the userID 1000 displayed, but I want the username.
This can happen if the username is longer than 8 characters (OR) id has no name. But, If you want the username in the ps output then try this,
ps -eo uname:20,pid,pcpu,pmem,sz,tty,stat,time,cmd | grep '[b]ash'
You can parse out the /proc entry if you are on Linux and if you just need a numeric pid (or are OK with it). Here is an example for the mysqld process:
grep -e '^Uid:' /proc/$(pidof mysqld)/status | cut -f 2
The shortest way I found so far ( $PID - ID of the process inspected):
ps -p $PID -o euid=
Here is an example for gedit process
grep -w Pid /proc/$(pidof gedit)/status | cut -f 2

Resources