Get the last(latest) process pid in linux - linux

I want to get the last/latest process pid in linux.Can anyone suggest me the command to find that ? But I don't know which process has started last.

Update: Thanks to William for the hint about awk.
Pre-condition: The process has still to be running.
I am not an UNIX expert, but I thought about the following approach:
ps aux --sort +start_time | tail -n 4 | awk 'NR==1{print $2}'
ps will list all processes and we are going to sort them by start_time. Afterwards we are going to take the fourth from the last line [0] of the output and awk will return the pid found in the second field.
root#unix ~ % sleep 10 &
[1] 3009
root#unix ~ % ps aux --sort +start_time | tail -n 4 | awk 'NR==1{print $2 " " $11}'
3009 sleep
root#unix ~ %
[0] The fourth line because there are three piped commands in my commandline.

If you want the process ID of the most recently executed background command you can use the ! variable. For example:
> gvim text.txt &
> echo $!
2842

Get PID:
#!/bin/bash
my-app & echo $!
Save PID in variable:
#!/bin/bash
my-app & export APP_PID=$!
Save all instances PID in text file:
#!/bin/bash
my-app & echo $! >>/tmp/my-app.pid
Save output, errors and PID in separated files:
#!/bin/bash
my-app >/tmp/my-app.log 2>/tmp/my-app.error.log & echo $! >>/tmp/my-app.pid
echo "my-app PID's: $(cat /tmp/my-app.pid)"

Related

execution of the command wmic causing issue for taskkill argument of /PID?

In a Cygwin bash script file when run "taskkill /PID $pid" failed with this response: ".ROR: Invalid argument/option -" after the line execution of the command wmic.
I had the following 6 lines in bash shell in a file namely killpid.sh:
#!/bin/sh
escontrolpid=$(tasklist | grep CONTROL | awk '{ print $2 }')
echo "escontrolpid is $escontrolpid"
#escontrolparentpid=$(wmic process where processid=$escontrolpid get parentprocessid | grep -v -i parentprocessid)
pid=$escontrolpid
echo "pid is" $pid
taskkill /PID $pid
When execute the file "killpid.sh" in Cygwin shell window like so:
./killpid.sh
It worked fine. Here were the output:
escontrolpid is 5804
pid is 5804
ERROR: The process with PID 5804 could not be terminated.
Reason: This process can only be terminated forcefully (with /F option).
But when change to these 6 lines (Uncomment the line # 4 and assign pid to the line 4's var):
escontrolpid=$(tasklist | grep CONTROL | awk '{ print $2 }')
echo "escontrolpid is $escontrolpid"
escontrolparentpid=$(wmic process where processid=$escontrolpid get parentprocessid | grep -v -i parentprocessid)
pid=$escontrolparentpid
echo "pid is" $pid
taskkill /PID $pid
It failed with this response:
escontrolpid is 5804
id is 1716
'.ROR: Invalid argument/option - '
Type "TASKKILL /?" for usage.
Note: process id of 1716 is the parent process of 5804 (i use command wmic to get the parent pid), and also the echo pid got the letter 'p' truncated to the output of the echo.
Why the execution of the command wmic causing issue for taskkill argument of /PID?
Further debugging, with inspect the length of the $pid, i found that the culprit is the extra characters as part of the value of $pid. Here was the modified script body of the killpid.sh:
escontrolpid=$(tasklist | grep CONTRO | awk '{ print $2 }')
echo escontrolpid is $escontrolpid
echo $escontrolpid > ./test.txt
sed 's/[^\x[0-9A-Fa-f][0-9A-Fa-f]]//g' ./test.txt | awk '{ print length }'
escontrolparentpid=$(wmic process where processid=$escontrolpid get
parentprocessid | grep -v -i parentprocessid | grep -v -e '^[[:space:]]*$')
pid=$escontrolparentpid
echo $pid > ./test.txt
sed 's/[^\x[0-9A-Fa-f][0-9A-Fa-f]]//g' ./test.txt | awk '{ print length }'
echo pid is $pid
taskkill /PID $pid
and the followings were the output:
escontrolpid is 5804
4
7
pid is 1716
'.ROR: Invalid argument/option - '
Type "TASKKILL /?" for usage.
The culprit $pid value is 7, and it should be 4.
How can i trim the extra 3 hex?
Finally, i figured it out, it was the extra carriage return character.
When i pipe the output of the $pid into a file, it has the extra line. This was the content of the file when run the cat command to view the file content:
Administrator#mywin /cygdrive/c/test
$ cat test.txt
1716 <- an extra space after 6
<- an blank line here
<- an blank line here
Note: There are two blank lines following 1716
So the fix was trim the extra carriage return character via this command:
tr -d '\r'

How to show Window title of GUI applications in terminal in Linux

I defined an interactive function called pk in my shell script to kill programs, such as pk emacs to kill emacs programs, but if multiple instances are running, then ask you to choose the pid to kill or kill them all.
This happens occasionally when one of my Emacs freezes since my CentOS in my company is old, but in my script function pk, I use ps to filter the commands and their PIDs, AFAIK ps tells no window title in this case, it just prints one or more "/usr/bin/emacs", no more details, and I don't know which PID freezes or no-response which I am going to kill.
I know I can use system tools like System Activity(KDE) to check the window title and kill the program, but I want to kill program in terminal using pk function, so is there any tool like ps but showing "window-title + command + pid" so I can use in my script to kill that program.
Since if you open a file using vim or emacs from terminal, ps with options will show the file it is editing, so I know the details of the PID and know which one to kill, so here, the Window title is like the Window title in System Activity.
Of course, if getting the Widow title is the wrong way, if anyone knows how to kill one of multiple instances of the same program just like I said, the answers would be welcome.
I just found another solution I can use in my pk function to kill the frozen emacs with the following line:
kill -SIGUSR2 (xprop | grep -i pid | grep -Po "[0-9]+")
The (xprop...) part will return the PID when you click on a GUI program using your mouse.
If anyone is interesting in my pk function, here it is(NOTE that I'm using fish-shell, so this is fish script function):
function pk --description 'kill processes containg a pattern'
set done 1
set result (psg $argv[1] | wc -l)
if test $result = 0
echo "No '$argv[1]' process is running!"
else if test $result = 1
psg $argv[1] | awk '{print $2}' | xargs kill -9
if test $status = 123 # Operation not permitted
read -p 'echo "Use sudo to kill it? [y/N]: "' -l arg
if test "$arg" = "y"
psg $argv[1] | awk '{print $2}' | xargs sudo kill -9
end
end
else
psg $argv[1]
while test $done = 1
read -p 'echo "Kill all of them or specific PID? [y/N/pid]: "' -l arg
if test "$arg" = "y"
psg $argv[1] | awk '{print $2}' | xargs kill -9
if test $status -eq 123 # Operation not permitted
read -p 'echo "Use sudo to kill them all? [y/N]: "' -l arg2
if test "$arg2" = "y"
psg $argv[1] | awk '{print $2}' | xargs sudo kill -9
end
end
set done 0
else if test $arg -a "$arg" != "y" -a "$arg" != "n"
# the fist cond in test means you typed something, RET will not pass
if test (psg $argv[1] | awk '{print $2}' | grep -i $arg)
kill -9 $arg #2>/dev/null
if test $status -eq 1 # kill failed
read -p 'echo "Use sudo to kill it? [y/N]: "' -l arg2
if test "$arg2" = "y"
sudo kill -9 $arg
end
end
echo -e "Continue...\n"
usleep 100000
psg $argv[1]
else if test "$arg" = "p"
# This may be used for frozen emacs specifically, -usr2 or -SIGUSR2
# will turn on `toggle-debug-on-quit`, turn it off once emacs is alive again
# Test on next frozen Emacs
kill -SIGUSR2 (xprop | grep -i pid | grep -Po "[0-9]+")
# kill -usr2 (xprop | grep -i pid | grep -Po "[0-9]+")
return
else
echo "PID '$arg[1]' is not in the list!"
echo
end
set done 1
else
# RET goes here, means `quit` like C-c
set done 0
end
end
end
end

Grep-ing while keeping first line

I am trying to understand this peculiar behavior. Basically, I'm trying to grep an output of a command while still keeping the first line/header. Thanks for the help in advance.
Success Case
ps -ef | { head -1; grep bash; }
Output:
UID PID PPID C STIME TTY TIME CMD
username 1008 1 0 Jan21 tty1 00:00:00 -bash
username 1173 1008 0 Jan21 tty1 00:00:00 -bash
Failed Case
ls -tlrh / | { head -1; grep tmp; }
Output:
total 100K
(i.e.: it ignores the /tmp folder)
#Jotne's answer is better, but sometimes you can use grep -E if you know something in the first line, then you can search for that OR the other thing you want like this with the pipe symbol to express the alternation:
ps -ef | grep -E "UID|bash"
Output
UID PID PPID C STIME TTY TIME CMD
502 510 509 0 8:01am ttys000 0:00.08 -bash
502 48806 510 0 10:18am ttys000 0:00.00 grep -E UID|bash
Try use awk, eks:
ls -tlrh / | awk 'NR==1 || /tmp/'
This will print line number 1 or lines with tmp
NR==1; print line number 1
/tmp/ print all lines that contains tmp
The reason this does not work, is that the first of the two processes (head -n1) reads more than it outputs. It eats up the output of ls and leaves nothing for the grep process; ps creates its output linewise.
The correct way to solve this would be to duplicate STDOUT for every process that needs it, as described here
redirect COPY of stdout to log file from within bash script itself
However here it would suffice to simply feed the reading scripts line by line to avoid any buffering issues:
ls -ltrh / | while { read a; } do echo $a; done | { head -n 1; grep tmp; }
However, this means that grep can not see the line(s), head has consumed.
well.. this works to...but just for noting a very convoluted solution
(ps aux | tee >(head -n1 >&3 ) | grep bio >&3 ) 3>&1
this is not as nice as i wanted it to be, fd3 usage makes it weird
note: it might even theorecally possible that grep output preceeds the header
pure sed solution ;)
ps aux|sed '1p;/kwork/p;d'

bash script returns empty ps results, same one-liner on CLI returns correctly

I have a bash init script that runs this command:
sudo -umyuser APPLICATION_ENV=production php script/push-server.php >> /var/log/push-server.log 2>&1 &
I then try to capture both pids and put them into a file:
echo $! > /var/log/push_server.pid
childpid=$(ps --no-heading --ppid $! | tail -1 | awk '{ print $1 }')
echo $childpid >> /var/log/push_server.pid
However, if I use the --no-heading flag it returns blank. If I run that very same ps command on the command line, it returns the proper pid number. The same happens if I modify the command a little bit like so:
childpid=$(ps --no-heading --ppid $! | awk '{NR>1}' | tail -1 | awk '{ print $1 }')
I've tried removing the NR, tail, adding the --no-header, and even going all the way down to just doing:
chidlpid=$(ps --no-heading --ppid $!)
and it still won't return the child pid.
Any ideas?
The second time you use $! you actually use the pid of the echo. Save it in a variable for later use.
Above statement is not true, as #mklement0 pointed out $! only updated when a new background process is started.
The most likely problem therefore is the timing: maybe the child process is not forked yet by the time the script checks for the pid.
Thanks for everyone who jumped in to help! The answer was indeed to add a sleep n:
sudo -umyuser APPLICATION_ENV=production php script/push-server.php >> /var/log/push-server.log 2>&1 &
mainpid=$!
echo $mainpid > /var/log/push_server.pid
sleep 3
childpid=$(ps --no-heading --ppid $mainpid | tail -1 | awk '{ print $1 }')
echo $childpid >> /var/log/push_server.pid
echo -n "push_server started on pid $mainpid $childpid"
return

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