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
Related
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'
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
I am configuring xbindkeys to change window focus using shortcuts.
For example, I managed to create a shortcut to focus on a an application window, let's say a terminator window:
wmctrl -xa terminator
Unfortunately it focuses always at the same terminator window, preventing me to cycle through the terminator windows.
Could you suggest me a command to focus on a terminator window and, if pressed again, will cycle through all the terminator windows, please?
UPDATE 30 Mar 2013
I modified this script
http://lars.st0ne.at/blog/switch%20between%20windows%20within%20the%20same%20application
to make a script such that
script.sh NAME
focus on application NAME or cycle through all the windows of NAME if a window of it is already focused, but it doesn't work properly.
Here is the script
win_class=$1 # 'terminator' # $1
# get list of all windows matching with the class above
win_list=$(wmctrl -x -l | grep -i $win_class | awk '{print $1}' )
# get id of the focused window
active_win_id=$(xprop -root | grep '^_NET_ACTIVE_W' | awk -F'# 0x' '{print $2}')
# get next window to focus on, removing id active
switch_to=$(echo $win_list | sed s/.*$active_win_id// | awk '{print $1}')
# if the current window is the last in the list ... take the first one
if [ "$switch_to" == '' ];then
switch_to=$(echo $win_list | awk '{print $1}')
fi
# switch to window
wmctrl -i -a $switch_to
The script does focus on a windows of the application, and cycle through them until it reach a window, I guess the last created. At that point, cycling doesn't work anymore.
I've found a problem in the script, if no window has focus.
May you try the following modified script:
#!/bin/bash
win_class=$1 # 'terminator' # $1
# get list of all windows matching with the class above
win_list=$(wmctrl -x -l | grep -i $win_class | awk '{print $1}' )
# get id of the focused window
active_win_id=$(xprop -root | grep '^_NET_ACTIVE_W' | awk -F'# 0x' '{print $2}')
if [ "$active_win_id" == "0" ]; then
active_win_id=""
fi
# get next window to focus on, removing id active
switch_to=$(echo $win_list | sed s/.*$active_win_id// | awk '{print $1}')
# if the current window is the last in the list ... take the first one
if [ "$switch_to" == '' ];then
switch_to=$(echo $win_list | awk '{print $1}')
fi
# switch to window
wmctrl -i -a $switch_to
The script works for me.
Anyway, it seems that the script does not find the active window in you case. Therefore it manages to switch to your application but fails to cycle through. It switches to the fist window in $win_list because, the sed command fails to remove the active window ( and all list entries before ) from $win_list.
Try the the following command:
xprop -root _NET_ACTIVE_WINDOW
The output should be something like this:
_NET_ACTIVE_WINDOW(WINDOW): window id # 0x2400005
The property "_NET_ACTIVE_WINDOW" is part of the EWMH standard. see: http://standards.freedesktop.org/wm-spec/wm-spec-1.3.html
Maybe you are using a non EWMH( Extended Window Manager Hint ) compliant window manager!
Which WM are you using?
... some window manager allow to enable EWMH compatibility via configuration or plugin.
After adapting the script by st0ne, I have a version that works generically (don't need to specify the app_name). Hope that is useful to somebody. :)
#!/bin/bash
active_win_id=`xprop -root | grep '^_NET_ACTIVE_W' | awk -F'# 0x' '{print $2}' | awk -F', ' '{print $1}'`
if [ "$active_win_id" == "0" ]; then
active_win_id=""
fi
app_name=`wmctrl -lx | grep $active_win_id | awk '{print $3}'`
workspace_number=`wmctrl -d | grep '\*' | cut -d' ' -f 1`
win_list=`wmctrl -lx | grep -ri $app_name | grep " $workspace_number " | awk '{print $1}'`
# get next window to focus on, removing id active
switch_to=`echo $win_list | sed s/.*$active_win_id// | awk '{print $1}'`
# if the current window is the last in the list ... take the first one
if [ "$switch_to" == "" ];then
switch_to=`echo $win_list | awk '{print $1}'`
fi
if [[ -n "${switch_to}" ]]
then
(wmctrl -ia "$switch_to") &
else
if [[ -n "$2" ]]
then
($2) &
fi
fi
exit 0
I encountered a small issue1 with tkt028's answer, but I liked what they were doing in terms of handling any generic application. But I also liked how st0ne's answer handles cycling through the windows of a specifically named application. So I combined the approaches.
My script takes an optional first argument to specify an application whose windows should be cycled. If no such windows are found, and if the optional second argument was provided, it falls back to launching the command specified by the second argument.
If no arguments are provided at all, then it just cycles through the windows of the currently active application.
#!/bin/bash
if [[ "$1" == "-h" || "$1" == "--help" ]]; then
echo "Cycle through windows of the active, or specified, application."
echo ""
echo "Usage: $(basename $0) [window_class_name [application_launcher]]"
echo ""
echo " window_class_name: regex string specifying an application's window name,"
echo " as specified by the third column of"
echo " 'wmctrl -l -x'"
echo " application_launcher: application to optionally launch if no windows"
echo " matching window_class_name are found"
echo ""
echo "If no arguments are specified, cycles through the windows of the active application."
exit
fi
# get ID of active window
active_win_id=`xprop -root | grep '^_NET_ACTIVE_W' | awk -F'# 0x' '{print $2}' | awk -F', ' '{print $1}'`
if [ "$active_win_id" == "0" ]; then
active_win_id=""
fi
if [[ -n "$1" ]]; then
# get app name from input argument
app_name="$1"
else
# get corresponding app name
app_name="${app_name:-$(wmctrl -lx | grep $active_win_id | awk '{print $3}')}"
fi
# get active workspace number
workspace_number=`wmctrl -d | grep '\*' | cut -d' ' -f 1`
# get list of windows corresponding to the desired app
win_list=`wmctrl -lx | grep -i $app_name | grep " $workspace_number " | awk '{print $1}'`
# get next window of app to focus on
#
# (Parses $win_list as a single string, removing everything except the token
# after the active ID. If active ID is sole token or last token, string will be
# left unmodified, producing an array from which we'll extract the first element.)
# Note: If active window was not of class app_name, then this will end up
# selecting the first window of app_name, if running. Otherwise, we'll fall
# through to launching a new instance of the app in the else of the next block.
switch_to=($(echo $win_list | sed "s/.*\<\(0x0\+\)\?$active_win_id\>\s*\(\<0x[0-9a-f]\+\>\).*/\2/"))
# if we have a valid window to switch to, do so
if [[ -n "${switch_to}" ]]; then
wmctrl -ia "${switch_to[0]}"
exit $?
else
# if the user specified a fallback application to run if target window
# was not found, try to launch it
if [[ -n "$2" ]]; then
$2 &
# check whether process corresponding to PID of background
# process we just launched is still running
ps -p $! > /dev/null
exit $?
else
exit $?
fi
fi
1 The recursive grep on this line in tkt028's answer didn't work in my environment. Maybe it's dependent on your version of grep.
win_list=`wmctrl -lx | grep -ri $app_name | grep " $workspace_number " | awk '{print $1}'`
I simply removed the r argument from the grep, and then their script worked as advertised.
win_list=`wmctrl -lx | grep -i $app_name | grep " $workspace_number " | awk '{print $1}'`
I have the following:
kill -9 `ps aux | grep php | awk '$9 !~ /[0-9]:[0-9]/' | awk '{print $2}'`
What it does is kill process that have been left abandoned by fcgid and kills them to free RAM. I want to run this as a cron every hour but would like to kill processes older then an hour. I'm just not sure how to modified the script to do that.
Try the following bash code :
for i in $(pidof php); do
pidtime=$(stat -c '%Y' /proc/$i)
now=$(date +%s)
((now - pidtime >= 3600)) && { kill $i; sleep 1; kill &>/dev/null -9 $i; }
done
and the crontab :
crontab -e
0 * * * * /path/to/the/script.bash
Solved with:
/bin/ps -Ao"command,pid,ppid"|/bin/grep ' 1$'|/bin/grep /php|/bin/awk '{ print $2; }'|/usr/bin/xargs --no-run-if-empty kill -9
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)"