how to combine a top command with a date column - linux

Good day,
I need to add a Column header "TIME" that will display the current time for each time the output is executed on a new line with the following code:
top -b -n 1 -p 984 -o +PID -o +VIRT | sed -n '7,12p' | awk '{printf "%1s %-4s\n",$1,$5}'
Output I'm looking for:
TIME PID VIRT
12:00:00 984 1024
12:16:01 984 995
12:44:29 984 1008
(The values is only for display, not correct)
also it should be in a endless loop with interval of 10s until user stops it.
everything is executed from PIDandVIRT.sh
(Linux script)
Thank you for the help in advance

I would recommend to use the ps command instead of top:
echo "TIME PID VSIZE"
while true ; do
echo "$(date +%H:%I:%S) $(ps -p 984 -o pid,vsize --no-headers)"
sleep 1
done

Set an awk variable to the result of the date command:
awk -v time=$(date '+%H:%M:%S') '{printf "%s %1s %-4s\n", time, $1, $5}'
To get it in a loop, use while
while :; do
top -b -n 1 -p 984 -o +PID -o +VIRT | sed -n '7,12p' | awk -v time=$(date '+%H:%M:%S') '{printf "%s %1s %-4s\n", time, $1, $5}'
sleep 10
done

Related

How to delete identical lines in my output files?

I have this script :
#!/bin/bash
ps -eo lstart,pid,cmd --sort lstart | while read line 2> /dev/null
do
if [ "$(date -d "${line::24}" "+%Y%m%d%H%M%S")" -gt "$(date -d "Thu Apr 7 00:55:38" "+%Y%m%d%H%M%S")" ] 2> /dev/null
then echo "Date : $(date -d "${line::24}" "+%d/%m/%Y %H:%M:%S") | PID & CMD : ${line:25:29}" >> process.log 2> /dev/null
fi 2> /dev/null
done
sort process.log | uniq > process.log
#sort process.log | uniq -u | tee process.log
My script runs automatically every 10 seconds, so I would like the identical lines to be deleted. As you can see, I tried with uniq but it doesn't work. I would like all lines in my file to be deleted if they are identical.
As I did, the second time the script is executed, there is nothing in the output file and I don't understand why.
I would also like nothing to be displayed in my terminal when the script runs. I used tee but when executing the uniq command, it returns an output in my terminal... How to remove it?
I thank you in advance for your help and wish you a good day
Thanks a lot
You should not parse ps output ever, especially not of lstart. Also, you are running date in the loop all the time, again and again.
I think something along this would be better to do:
some_date=$(date -d "Thu Apr 7 00:55:38" +%s)
now=$(date +%s)
how_much_time_ago=$(( now - some_date ))
ps -eo etimes,pid,cmd --sort etimes |
awk -v v="$how_much_time_ago" '$1 > v' |
while IFS=' ' read line etimes pid cmd; do
printf "Date : %s | PID & CMD : %s %s\n" \
"$(date -d "$((now - etimes))" "+%d/%m/%Y %H:%M:%S")" \
"$pid" "$cmd"
done |
sort |
uniq > process.log
Note that you can pipe the output of a while .... done | stuff loop to another thing normally. Instead of sprinkling 2>/dev/null everywhere, try to actually solve the issue, not hide the error.

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'

Grep count of processes running more than x minutes

My goal is to grep for a count of processes older than 'x' minutes in bash.
So far, I can grep for all the process execution times:
ps -eo etime,cmd | grep mysuperspecialprocess.sh | grep -Ev 'grep' | awk '{print $1}'
I pipe a wc -l to get a count at the end.
How can I grep or loop through the result to restrict it to processes older than a certain number of minutes?
Give this tested version a try.
It searches a specified running process, and count all occurences which has an associated elapsed time greater than a specified number of seconds.
Set parameters' values first and run it.
$ cat ./script.sh
#!/bin/bash --
process_name=mysuperspecialprocess.sh
elapsed_time_seconds=600
ps -eo etimes,cmd | fgrep "${process_name}" | fgrep -v fgrep | ( count=0 ; while read etimes cmd ; do \
if [ $etimes -gt $elapsed_time_seconds ] ;\
then \
count=$((count+1)) ;\
fi ;\
done ; echo $count )
etimes instructs ps to display seconds.
awk to the rescue!
starting with the etime field you can do something similar to this, ignores seconds.
$ awk 'NR>1{n=split($1,a,":"); # split the field
if(n==2) mins=a[1]+0; # if hours not present set mins
else {d=split(a[1],h,"-"); # check for days
hours=(d==2?h[1]*24+h[2]:h[1]); # incorporate days in hours
mins=hours*60+a[2]} # compute mins
print $1, mins}' etimes
00:04 0
02:30:44 150
01:03:11 63
1-01:01:01 1501
3-00:02:00 4322

Linux - Extract core utilization for a single process to a file

I am trying to figure out how to extract the cpu core utilization for a SINGLE process in linux and parse it. I know that I can get the overall core utilization via top and then press "1". I am already able to parse that. However, now I want to do the same thing for a single process. I tried it with ps and calculating the core utilization myself but I am not so sure if my script is accurate enough, something seems off. (Note that this version calculates overall core utilization since it is WIP) I get errors like this after a while in my terminal:
test.sh: line 31: +: syntax error: operand expected (error token is
"+")
I cannot figure out why this error just randomly occurs.
#!/bin/env bash
read -p "Enter PID to observe:" pid
run=false
ps -p $pid -L -o cputime,etime,psr,pcpu
for (( u = 1 ; u <= 100 ; u++ ))
do
lines=$(ps -p $pid -L -o psr,pcpu | awk 'END{print NR}')
for (( i=1; i<=$lines; i++))
do
core=$(ps -p $pid -L -o psr,pcpu | awk 'NR=='$i'{print $1}')
if [ $run == false ]
then cpuTimeS=+$(ps -p $pid -L -o cputime,etime | awk 'NR=='$i'{print $1}' | awk -F : '{ printf("%.2f\n", $1*60+$2*60+$3); }')
elapsedTimeS=+$(ps -p $pid -L -o cputime,etime | awk 'NR=='$i'{print $2}' | awk -F : '{ printf("%.2f\n", $1*60+$2*60+$3); }')
cpuTimeSi=${cpuTimeS%.*}
elapsedTimeSi=${elapsedTimeS%.*}
cpuTimeSiResult=$(( cpuTimeSi + cpuTimeSiResult ))
elapsedTimeSiResult=$(( elapsedTimeSi + elapsedTimeSiResult ))
else
cpuTimeE=+$(ps -p $pid -L -o cputime,etime | awk 'NR=='$i'{print $1}' | awk -F : '{ printf("%.2f\n", $1*60+$2*60+$3); }')
elapsedTimeE=+$(ps -p $pid -L -o cputime,etime | awk 'NR=='$i'{print $2}' | awk -F : '{ printf("%.2f\n", $1*60+$2*60+$3); }')
cpuTimeEi=${cpuTimeE%.*}
elapsedTimeEi=${elapsedTimeE%.*}
cpuTimeEiResult=$(( cpuTimeEi + cpuTimeEiResult ))
elapsedTimeEiResult=$(( elapsedTimeEi + elapsedTimeEiResult ))
fi
done
if [ "$run" = true ]
then result=$( echo "scale=2; ($cpuTimeEiResult - $cpuTimeSiResult) / ($elapsedTimeEiResult - $elapsedTimeSiResult) * 100.0" | bc)
echo "RESULT:" $result
echo "cpuTimeSTART:" $cpuTimeSiResult
echo "elapsedTimeSTART:" $elapsedTimeSiResult
echo "cpuTimeEND:" $cpuTimeEiResult
echo "elapsedTimeEND:" $elapsedTimeEiResult
fi
sleep 1
if [ "$run" = false ]
then run=true
else
run=false
fi
done
Are there any ideas on how I could solve this better?
I am glad for any advice
Looking at your actual request to get the CPU utilization from a particular process; this could be done in less lines; e.g. below is the CPU usage after giving a seq command.
#using the process name
$ ps -C seq -o %cpu
%CPU
10.4
#using the process id
$ ps -p 5710 -o %cpu
%CPU
10.4

How to separate columns in ps -ef command

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

Resources