Mac Terminal Open Command - Save PID of Opened Application? - xcode

I'd like to open an xcode workspace in terminal, wait some time, then close that workspace (xcode has some hidden magic it does on projects that makes this necessary in an automated build process).
So something like-
pid=`open proj.xcworkspace`
sleep 30
kill $pid
Because multiple xcode projects may be running in the same time. I can't simply kill xcode, just the process I started.
How can I get the PID of an application I open in terminal?

You can catch the current Process ID with $$.
Or you can search for Process IDs with ps -C PROGRAMM_NAME -o pid=.
suleiman#antec:~$ ps -C icedove -o pid=
887
suleiman#antec:~$ ps -C vlc -o pid=
29405
Addition...
Here is a working example of what I mean ...
#!/bin/bash
i=0
while [ "$i" -le 10 ]
do
example.sh &
Pid[$i]=$(ps -C "example.sh" -o "pid=")
Pid[$i]=$(echo "${Pid[$i]}" | tail -n 1)
#echo "${Pid[$i]}"
i=$(($i +1))
done
for PID in "${Pid[#]}"
do
kill "$PID"
done
exit 0

Related

Getting a Process ID & Assigned to a variable and kill the process in Bash Script

I store in a variable an executed command like so:
pio device monitor -p COM22 -b 115200 --no-reconnect | grep -E -o -m 1 '[A-Za-z0-9]{12}'
pio device monitor is a command to watch custom logs from an esp32, I use these logs to extract the wanter value (something like C8F09E0AA13C).
I want to run this command in the background and when the command return something, kill the process.
The script works as expected. The command stored in IDFound run in the background and as soon it found something the loop stop and the process is killed and I get the wanted value.
# /bin/bash
regex='[A-Za-z0-9]{12}'
port=COM22
unset -v IDFound
if ! [[ $IDFound =~ $regex ]] ; then
echo 'Please press the reset button of the ESP-prog'
IDFound=$(pio device monitor -p $port -b 115200 --no-reconnect | grep -E -o -m 1 $regex &)
# Get PID of this command
pid=$(ps -ef | awk '/pio/{print $2}')
# kill the process with PID
kill $pid
fi
echo $IDFound
But my problem is that I get PID with the pio keyword and I run another similar command in my script. I don't want to kill the wrong process.
I want to get the PID with $! to avoid mistake. How could I achieve that ?

How to kill a process group with kill in bash?

I have a script which is much more complicated but I managed to produce a short script that exhibits the same problem.
I create a process and make it a session leader and then send SIGINT to it. The kill builtin doesn't fail but the process doesn't get killed either (i.e. the default behaviour for SIGINT is to kill). I tried with kill -INT -pid (which should be equivalent to what I do currently) and the /bin/kill command but the behaviour is the same.
The script is as follows:
#!/bin/bash
# Run in a new session so that I don't have to kill the shell
setsid bash -c "sleep 50" &
procs=$(ps --ppid $$ -o pid,pgid,command | grep 'sleep' | head -1)
if [[ -z "$procs" ]]; then
echo "Couldn't find process group"
exit 1
fi
PID=$(echo $procs | cut -d ' ' -f 1)
pgid=$(echo $procs | cut -d ' ' -f 2)
if ! kill -n SIGINT $pgid; then
echo "kill failed"
fi
echo "done"
ps -P $pgid
My expectation is that the last ps command shouldn't report anything (as kill didn't report failure and hence the process should have died) but it does.
I am looking for an explanation of the above noted behaviour and how I can kill a process group (i.e. both the bash and the sleep it starts -- the setsid line above) running in a separate session.
I think you'll find that sleep ignores SIGINT. Take a look at the signals of your sleep command and see. On my Linux box I find:
SigIgn: 0000000000000006
The second bit from the right is set (6 = 4 + 2 + 0), and from the above link:
--> 2 = SIGINT
Try send a HUP, and you'll find it does kill the sleep.

SHOUTcast daemon script not functioning properly

I've got a SHOUTcast server running on Ubuntu. The server process is running great, but I can't seem to get the daemon script to function properly. Following a couple tutorials I found I came up with this:
#!/bin/sh
CONFIG="/home/apps/shout32/sc_plex.conf"
DAEMON="/home/apps/shout32/sc_serv"
case "$1" in
start)
echo "Starting SC..."
$DAEMON $CONFIG > /dev/null 2>&1 &
;;
stop)
echo "Stopping SC..."
kill -9 `ps -C sc_serv -o pid --no-headers`
;;
restart)
echo "Rebooting SC..."
kill -9 `ps -C sc_serv -o pid --no-headers`
$DAEMON $CONFIG > /dev/null 2>&1 &
;;
*)
echo "usage: service sc32d {start | stop | restart}"
exit 1
;;
esac
This however does not work. I didn't know what a lot of this meant, so I started to break it down line by line. If I remove the /dev/null stuff - which as I now understand keeps the program running 'silent' in the background - I get this message, and the program closes:
root#streams3:/etc/init.d# service sc32d start
Starting SC...
root#streams3:/etc/init.d# 2013-05-21 14:41:50 E msg:<***> logger could not open file logs/sc_serv.log
2013-05-21 14:41:50 I msg:<***> Logger shutdown
root#streams3:/etc/init.d#
root#streams3:/etc/init.d# ps -C sc_serv
PID TTY TIME CMD
root#streams3:/etc/init.d#
I was still in the process of researching what exactly /dev/null did and why, so I wanted to run those commands with all the /dev/null stuff by hand, which I did, and that's where I got some sort of error code:
root#streams3:/etc/init.d# /home/apps/shout32/sc_serv /home/apps/shout32/sc_plex.conf > /dev/null 2>&1 &
[2] 2261
root#streams3:/etc/init.d#
[2]- Exit 255 /home/apps/shout32/sc_serv /home/apps/shout32/sc_plex.conf > /dev/null 2>&1
root#streams3:/etc/init.d# ps -C sc_serv
PID TTY TIME CMD
Unfortunately from the brief amount of research I did it sounds like 'Exit 225' is like a catch-all error code for codes that are outside of the acceptable range of codes.
The interesting part of the whole issue is this: When I navigate to the /home/apps/shout32/ folder, and run the commands there, without the full path... damn thing works:
root#streams3:/home/apps/shout32# ./sc_serv sc_plex.conf > /dev/null 2>&1 &
[2] 2245
root#streams3:/home/apps/shout32#
root#streams3:/home/apps/shout32# ps -C sc_serv
PID TTY TIME CMD
2245 pts/0 00:00:00 sc_serv
So, something is messing up because the script file is in /etc/init.d/ and not in the folder the application is in? As far as I know I followed every step in the published tutorials for setting up SHOUTcast in Ubuntu and then making a daemon... I don't think I missed anything. I have a feeling the solution is either staring me right in the face or its some sort of obscure permissions thing that's a bit over my head.
But any help would be greatly appreciated!
So, based on an answer below I added cd /home/apps/shout32/ to the START command in my script, also added pwd and ls... to see if we could eliminate the fact that the script couldn't find the /log/ directory.
So now my script is:
CONFIG="/home/apps/shout32/sc_plex.conf"
DAEMON="/home/apps/shout32/sc_serv"
cd /home/apps/shout32/
case "$1" in
start)
echo "Starting SC..."
cd /home/apps/shout32/
pwd
ls
$DAEMON $CONFIG &
;;
stop)
echo "Stopping SC..."
kill -9 `ps -C sc_serv -o pid --no-headers`
;;
restart)
echo "Rebooting SC..."
kill -9 `ps -C sc_serv -o pid --no-headers`
$DAEMON $CONFIG &
;;
*)
echo "usage: service sc32d {start | stop | restart}"
exit 1
;;
esac
I got this:
admin#streams3:/etc/init.d$ service sc32d start
Starting SC...
/home/apps/shout32
changes.txt readme.txt sc_serv_debug.conf
config_builder sc_plex.conf sc_serv_public.conf
control sc_serv sc_serv_relay.conf
docs sc_serv2_linux_07_31_2011.tar sc_serv_simple.conf
logs sc_serv_basic.conf tos.txt
admin#streams3:/etc/init.d$ 2013-06-05 17:52:08 E msg:<***> logger could not open file logs/sc_serv.log
2013-06-05 17:52:08 I msg:<***> Logger shutdown
your second snippet contains logger could not open file logs/sc_serv.log. So it tries to write to a file sc_serv.log which it either expects or wants to create in the directory logs which it expects in the current directory. This also explains that it works when you cd to /home/apps/shout32/ first. I guess there's a file /home/apps/shout32/logs/sc_serv.log.
can you configure the location of that file?
can't you just add some cd ... at the start of the script?

Kill a process generated by for loop after certain time

I have some code that tends to hang randomly inside it's 'for loop'. I'm looking for a solution that will automatically kill the ssh session's PID if it exists for 5 seconds. I'm killing the hung processes right now manually, but I want to put this in cron so automatic PID killing would be awesome.
for host in `cat $WORKDIR/linux_hosts.txt $WORKDIR/aix_hosts.txt`
do
ssh -o LogLevel=QUIET -o ConnectTimeout=2 -t $host "cat /etc/passwd" >> $FILEDIR/$host
done
Thanks for the help!
Run all the ssh processes in the background, then wait 5 seconds. Once sleep returns, use jobs -p to get the process IDs of any background jobs still running, and kill them.
cat "$WORKDIR"/{linux_hosts.txt,aix_hosts.txt} | while read host; do
ssh -o LogLevel=QUIET -o ConnectTimeout=2 -t "$host" "cat /etc/passwd" >> "$FILEDIR/$host" &
done
sleep 5
kill $(jobs -p) 2>/dev/null
Use timeout:
for host in `cat $WORKDIR/linux_hosts.txt $WORKDIR/aix_hosts.txt`
do
timeout 5s ssh -o LogLevel=QUIET -o ConnectTimeout=2 -t $host \
"cat /etc/passwd" >> $FILEDIR/$host
done
This will find and kill all ssh process older than 5 minutes.
cd /proc
kill $(find $(pidof ssh) -maxdepth 0 -mmin +5)

Wait for a process to finish

Is there any builtin feature in Bash to wait for a process to finish?
The wait command only allows one to wait for child processes to finish.
I would like to know if there is any way to wait for any process to finish before proceeding in any script.
A mechanical way to do this is as follows but I would like to know if there is any builtin feature in Bash.
while ps -p `cat $PID_FILE` > /dev/null; do sleep 1; done
To wait for any process to finish
Linux (doesn't work on Alpine, where ash doesn't support tail --pid):
tail --pid=$pid -f /dev/null
Darwin (requires that $pid has open files):
lsof -p $pid +r 1 &>/dev/null
With timeout (seconds)
Linux:
timeout $timeout tail --pid=$pid -f /dev/null
Darwin (requires that $pid has open files):
lsof -p $pid +r 1m%s -t | grep -qm1 $(date -v+${timeout}S +%s 2>/dev/null || echo INF)
There's no builtin. Use kill -0 in a loop for a workable solution:
anywait(){
for pid in "$#"; do
while kill -0 "$pid"; do
sleep 0.5
done
done
}
Or as a simpler oneliner for easy one time usage:
while kill -0 PIDS 2> /dev/null; do sleep 1; done;
As noted by several commentators, if you want to wait for processes that you do not have the privilege to send signals to, you have find some other way to detect if the process is running to replace the kill -0 $pid call. On Linux, test -d "/proc/$pid" works, on other systems you might have to use pgrep (if available) or something like ps | grep "^$pid ".
I found "kill -0" does not work if the process is owned by root (or other), so I used pgrep and came up with:
while pgrep -u root process_name > /dev/null; do sleep 1; done
This would have the disadvantage of probably matching zombie processes.
This bash script loop ends if the process does not exist, or it's a zombie.
PID=<pid to watch>
while s=`ps -p $PID -o s=` && [[ "$s" && "$s" != 'Z' ]]; do
sleep 1
done
EDIT: The above script was given below by Rockallite. Thanks!
My orignal answer below works for Linux, relying on procfs i.e. /proc/. I don't know its portability:
while [[ ( -d /proc/$PID ) && ( -z `grep zombie /proc/$PID/status` ) ]]; do
sleep 1
done
It's not limited to shell, but OS's themselves do not have system calls to watch non-child process termination.
FreeBSD and Solaris have this handy pwait(1) utility, which does exactly, what you want.
I believe, other modern OSes also have the necessary system calls too (MacOS, for example, implements BSD's kqueue), but not all make it available from command-line.
From the bash manpage
wait [n ...]
Wait for each specified process and return its termination status
Each n may be a process ID or a job specification; if a
job spec is given, all processes in that job's pipeline are
waited for. If n is not given, all currently active child processes
are waited for, and the return status is zero. If n
specifies a non-existent process or job, the return status is
127. Otherwise, the return status is the exit status of the
last process or job waited for.
Okay, so it seems the answer is -- no, there is no built in tool.
After setting /proc/sys/kernel/yama/ptrace_scope to 0, it is possible to use the strace program. Further switches can be used to make it silent, so that it really waits passively:
strace -qqe '' -p <PID>
All these solutions are tested in Ubuntu 14.04:
Solution 1 (by using ps command):
Just to add up to Pierz answer, I would suggest:
while ps axg | grep -vw grep | grep -w process_name > /dev/null; do sleep 1; done
In this case, grep -vw grep ensures that grep matches only process_name and not grep itself. It has the advantage of supporting the cases where the process_name is not at the end of a line at ps axg.
Solution 2 (by using top command and process name):
while [[ $(awk '$12=="process_name" {print $0}' <(top -n 1 -b)) ]]; do sleep 1; done
Replace process_name with the process name that appears in top -n 1 -b. Please keep the quotation marks.
To see the list of processes that you wait for them to be finished, you can run:
while : ; do p=$(awk '$12=="process_name" {print $0}' <(top -n 1 -b)); [[ $b ]] || break; echo $p; sleep 1; done
Solution 3 (by using top command and process ID):
while [[ $(awk '$1=="process_id" {print $0}' <(top -n 1 -b)) ]]; do sleep 1; done
Replace process_id with the process ID of your program.
Blocking solution
Use the wait in a loop, for waiting for terminate all processes:
function anywait()
{
for pid in "$#"
do
wait $pid
echo "Process $pid terminated"
done
echo 'All processes terminated'
}
This function will exits immediately, when all processes was terminated. This is the most efficient solution.
Non-blocking solution
Use the kill -0 in a loop, for waiting for terminate all processes + do anything between checks:
function anywait_w_status()
{
for pid in "$#"
do
while kill -0 "$pid"
do
echo "Process $pid still running..."
sleep 1
done
done
echo 'All processes terminated'
}
The reaction time decreased to sleep time, because have to prevent high CPU usage.
A realistic usage:
Waiting for terminate all processes + inform user about all running PIDs.
function anywait_w_status2()
{
while true
do
alive_pids=()
for pid in "$#"
do
kill -0 "$pid" 2>/dev/null \
&& alive_pids+="$pid "
done
if [ ${#alive_pids[#]} -eq 0 ]
then
break
fi
echo "Process(es) still running... ${alive_pids[#]}"
sleep 1
done
echo 'All processes terminated'
}
Notes
These functions getting PIDs via arguments by $# as BASH array.
Had the same issue, I solved the issue killing the process and then waiting for each process to finish using the PROC filesystem:
while [ -e /proc/${pid} ]; do sleep 0.1; done
There is no builtin feature to wait for any process to finish.
You could send kill -0 to any PID found, so you don't get puzzled by zombies and stuff that will still be visible in ps (while still retrieving the PID list using ps).
If you need to both kill a process and wait for it finish, this can be achieved with killall(1) (based on process names), and start-stop-daemon(8) (based on a pidfile).
To kill all processes matching someproc and wait for them to die:
killall someproc --wait # wait forever until matching processes die
timeout 10s killall someproc --wait # timeout after 10 seconds
(Unfortunately, there's no direct equivalent of --wait with kill for a specific pid).
To kill a process based on a pidfile /var/run/someproc.pid using signal SIGINT, while waiting for it to finish, with SIGKILL being sent after 20 seconds of timeout, use:
start-stop-daemon --stop --signal INT --retry 20 --pidfile /var/run/someproc.pid
Use inotifywait to monitor some file that gets closed, when your process terminates. Example (on Linux):
yourproc >logfile.log & disown
inotifywait -q -e close logfile.log
-e specifies the event to wait for, -q means minimal output only on termination. In this case it will be:
logfile.log CLOSE_WRITE,CLOSE
A single wait command can be used to wait for multiple processes:
yourproc1 >logfile1.log & disown
yourproc2 >logfile2.log & disown
yourproc3 >logfile3.log & disown
inotifywait -q -e close logfile1.log logfile2.log logfile3.log
The output string of inotifywait will tell you, which process terminated. This only works with 'real' files, not with something in /proc/
Rauno Palosaari's solution for Timeout in Seconds Darwin, is an excellent workaround for a UNIX-like OS that does not have GNU tail (it is not specific to Darwin). But, depending on the age of the UNIX-like operating system, the command-line offered is more complex than necessary, and can fail:
lsof -p $pid +r 1m%s -t | grep -qm1 $(date -v+${timeout}S +%s 2>/dev/null || echo INF)
On at least one old UNIX, the lsof argument +r 1m%s fails (even for a superuser):
lsof: can't read kernel name list.
The m%s is an output format specification. A simpler post-processor does not require it. For example, the following command waits on PID 5959 for up to five seconds:
lsof -p 5959 +r 1 | awk '/^=/ { if (T++ >= 5) { exit 1 } }'
In this example, if PID 5959 exits of its own accord before the five seconds elapses, ${?} is 0. If not ${?} returns 1 after five seconds.
It may be worth expressly noting that in +r 1, the 1 is the poll interval (in seconds), so it may be changed to suit the situation.
On a system like OSX you might not have pgrep so you can try this appraoch, when looking for processes by name:
while ps axg | grep process_name$ > /dev/null; do sleep 1; done
The $ symbol at the end of the process name ensures that grep matches only process_name to the end of line in the ps output and not itself.

Resources