How to separate columns in ps -ef command - linux

I have the command:
ps -ef | grep kde | tr -s ' ' '#'
I`m getting output like this :
user2131#1626#1584#0#15:50#?#00:00:00#/bin/sh#/usr/bin/startkdeere
how can I get # symbol only for column separation using linux or smth else like awk ?

Use pgrep to get your PIDs instead of using ps. pgrep will eliminate the grep issue where one of the processes you discover is the grep doing your filtering.
You can also specify the output of the ps command itself using the -o or -O option. You can do this to get the fields you want, and eliminate the header.
You can also use the read command to parse your output. The only field you have with possible blank space is the last one -- the command and arguments.
ps -o uid= -o gid= -o tty= -o args= -p $(pgrep kde) | while read uid gid tty cmd
do
echo "UID = $uid PID = $pid TTY = $tty"
echo "Command = $cmd"
done
The while will split on whitespace except for the $cmd which will include all the leftover fields (i.e. the entire command with arguments).
The ps command differs from platform to platform, so read the manpage on ps.

Nasty but it works. Tweak the number 8 to suit the number of columns your variant of ps outputs.
ps -ef | awk -v OFS="" '{ for(i=1; i < 8; i++) printf("%s#",$i); for(i=8; i <= NF; i++) printf("%s ", $i); printf("\n")}'

If you mean process your output with '#' as a column/field separator, in awk you can use -F:
echo "user2131#1626#1584#0#15:50#?#00:00:00#/bin/sh#/usr/bin/startkdeere" | awk -F'#' -v OFS='\t' '{$1=$1;print $0}'
Output:
user2131 1626 1584 0 15:50 ? 00:00:00 /bin/sh /usr/bin/startkdeere

Related

Identify processes running more than 3 hrs in linux

I want to find out processes running more than 3 hrs, I have written a command for this but it's not returning expected output
ps -u <user> -o pid,stime,pcpu,pmem,etime,cmd --sort=start_time | \
grep <searchString> | grep -v grep| awk '{print $5}' | \
sed 's/:|-/ /g;'| awk '{print $4" "$3" "$2" "$1"}' | \
awk '$1+$2*60+$3*3600+$4*86400 > 10800'
but it's printing the values of etime in output. But expected output is, command should print the values of "pid,stime,pcpu,pmem,etime,cmd"
I am not able to find exact issue with this.
You are executing "awk '{print $5}'" which is taking in the input and printing out only column 5 which in your case is "etime" , everything from this point on is lost.
If your system supports etimes (notice the s on the end), you can easily do this with
ps -eo pid,etimes,etime,comm,user,tty | awk '{if ( $2>10800) print $0}'
on a system not supporting etimes which has a standard output of etime which hh:mm:ss or just mm:ss if no hours have passed
ps -eo pid,etime,comm,user,tty | awk '{seconds_old=10800 ; split($2,a,":",sep) ; if(length(a) < 3) b = (a[1] *60) + (a[2]) ; else b=((a[1]*3600) + (a[2] *60) + (a[3])) ; if(b > seconds_old ) print $0}'
Adjust "seconds_old" to change the age you want to test for:
There are various other methods of doing this using Find for example:
explained here:
https://serverfault.com/questions/181477/how-do-i-kill-processes-older-than-t
However, the solution should match your expected output
Try this:
ps -u <user> -o pid,stime,pcpu,pmem,etime=,cmd --sort=start_time|grep <searchString>|while read z;do tago=$(echo $z|awk '{print $5}'|sed -E 's/(:|-)/ /g'| awk '{print $4+$3*60+$2*3600+$1*86400}');if [ $tago -ge 10800 ];then echo $z;fi;done
It prints only processes >= 10800 secs old.
You can readjust the output further to fit your needs.
Able to find running process for more than 3 hrs with below command.
ps -u <user> -o pid,stime,pcpu,pmem,etime,cmd --sort=start_time |grep -v grep|awk 'substr($0,23,2) > 3'

How to pipe custom script in bash?

I have file, where each line is pid of some process. What I would like to achieve, is displaying file descriptors summary.
So basically my steps are like this:
ps -aux | grep -E 'riak|erlang' | tr -s " " | cut -f2 -d " " | xargs lsof -a -p $param | (wc -l per process)
I am lost here: $param I don't know how to put it from stdin, also I don't have an idea how to make wc -l grouped per each lsof -a -p result, not for total result - I am expecting number of open files per process, not by them all.
Bonus question: How to convert such input:
123 foo-exe
234 bar-exe
(first column pid, second name)
to result like
123 foo-exe 1234
234 foo-exe 12344
where first column is pid, second is name, third is number of open files.
I know it could be different way of doing it (which I would like to know), but knowledge how to do it using bash tools would be nice :)
Assuming that riak, erlang are user names.
ps -e -o pid=,comm= -U riak,erlang | while read pid comm; do lsof=`lsof -a -p $param | wc -l`; echo $pid $comm $lsof; done
Pure lsof+awk based approach (should be faster) than earlier approach.
{ lsof -u riak +c 0; lsof -u erlang +c 0; } | awk '{cmd[$2]=$1;count[$2]++;}function cmp_num_idx(i1, v1, i2, v2) {return (i1 - i2);} END{PROCINFO["sorted_in"]="cmp_num_idx"; for (pid in cmd){ printf "%10d %20s %10d\n", pid, cmd[pid], count[pid];}}'

Extract value from result Linux

I have a Linux command line to display a certain result. From the result, I would like to grep it or use awk to pull out a specific value. This is the result of the command line:
OK 0 seconds over max, 0 active processes, next process in the future|'overmax'=0s;300;600 'active'=0 'nextoldest'=-1153s
All I want is to display on the value after 'active'=? which would be in this instance 0
try this grep line:
grep -Po "'active'=\K\S*"
You could use egrep like this :
egrep -o "'active'=[^\ ]+"
Example :
[ ~]$ str="OK 0 seconds over max, 0 active processes, next process in the future|'overmax'=0s;300;600 'active'=0 'nextoldest'=-1153s"
[ ~]$ echo $str|egrep -o "'active'=[^\ ]+"
'active'=0
[ ~]$
If you're sure that the right value is numeric, you can further restrict the pattern like this :
egrep -o "'active'=[0-9]+"
You could use sed too :
[ ~]$ echo $str|sed "s/.*\('active'=[^\ ]*\).*/\1/g"
'active'=0
And if you want to get only the right value :
[ ~]$ echo $str|sed "s/.*'active'=\([^\ ]*\).*/\1/g"
0
You could use awk too but I think that is not the better solution in this case. But just for fun :
[ ~]$ echo $str|awk -F " " '{for (i=1; i <= NF; i++){if($i ~ ".?active.?="){print $i}}}'
'active'=0
N.B : egrep is equivalent to "-E" option of grep.
Another gnu awk
awk '{print gensub(/.*active.=(.*) .*/,"\\1","g")}' file
0
awk '{ match($0,/'active'=(.*) /,a); print a[1]}' file

Bash capturing output of awk into array

I am stuck on a little problem. I have a command which pipes output to awk but I want to capture the output of to an array one by one.
My example:
myarr=$(ps -u kdride | awk '{ print $1 }')
But that capture all my output into one giant string separated by commas:
output: PID 3856 5339 6483 10448 15313 15314 15315 15316 22348 29589 29593 32657 1
I also tried the following:
IFS=","
myarr=$(ps -u kdride | awk '{ print $1"," }')
But the output is: PID, 3856, 5339, 6483, 10448, 15293, 15294, 15295, 15296, 22348, 29589, 29593, 32657,
1
I want to be able to capture each individual pid into its own array element. Setting IFS = '\n' does not do anything and retains my original output. What change do I need to do to make this work?
Add additional parentheses, like this:
myarr=($(ps -u kdride | awk '{ print $1 }'))
# Now access elements of an array (change "1" to whatever you want)
echo ${myarr[1]}
# Or loop through every element in the array
for i in "${myarr[#]}"
do
:
echo $i
done
See also bash — Arrays.
Use Bash's builtin mapfile (or its synonym readarray)
mapfile -t -s 1 myarr < <(ps -u myusername | awk '{print $1}')
At least in GNU/Linux you can format output of ps, so no need for awk and -s 1
mapfile -t myarr < <(ps -u myusername -o pid=)

Linux awk command doesn't print integers correctly?

Can someone explain why this command doesn't print out a list of PID without the newline?
I want output like:
1234 5678 123 456
I tried all these, and none of them work
ps -eww --no-headers -o pid,args | grep 'usr' | awk '{ printf "%d ", $1 }'
ps -eww --no-headers -o pid,args | grep 'usr' | awk '{ printf "%s ", $1 }'
ps -eww --no-headers -o pid,args | grep 'usr' | awk '{ print $1 }' | tr '\n' ''
ps -eww --no-headers -o pid,args | grep 'usr' | awk '{ print $1 }' | tr -d '\n'
I just found out bash works fine, but not zsh in my case
zsh has a feature of letting the user know that the last output line was partial (i.e. there were no final newline). For more details on this you can look up PROMPT_CR, PROMPT_SP and PROMPT_EOL_MARK in man zshoptions.
You can add PROMPT_EOL_MARK='' to your ~/.zshrc to make the partial line indicator empty, but I would advise against it: now we know that it's just a feature, and sometimes we can notice a problem with our data if we leave it enabled. On a reasonably powerful terminal, the percent sign (the default when PROMPT_EOL_MARK is unset) is output bold and inverted, so it can't be confused with a piece of actual output.
Your command's output is a list of pids exactly as you desired. Adding a final newline makes it also look right with zsh:
ps -eww --no-headers -o pid,args | awk '/usr/ { printf "%d ", $1 } END {print""}'
(using also another answer's idea of getting rid of grep using the power of awk).
It does for me like this:
ps -eww --no-headers -o pid,args | awk '/usr/{printf "%d ",$1}'
I.e. awk can search for strings matching regular expressions, so you don't really need grep when using awk.

Resources