How to keep the internal shell script running while the main shell script ends? - bash

I am trying to create one script which check for a running process and start it if it is not running.
Here is test.sh
#!/bin/bash
if pgrep infiloop > /dev/null ;
then
echo "Process is running."
else
exec /u/team/infiloop.sh > /u/team/infiloopOutput.txt
echo "Process was not running."
fi
And infiloop.sh
#!/bin/sh
while true
do
echo "helllo"
sleep 2
done
Now when i run the 1st script , it starts the script but after it start it doesn't allow me to run another command.
Output:
[user#host ~]$ ./checkforRunningJob.sh
^C
I have to press Ctrl+C, Ctrl+Z, and once i do that my infinite script also stop.
Could you please check.
Thanks.

You can put the process in the background with &:
#!/bin/bash
if pgrep infiloop > /dev/null ;
then
echo "Process is running."
else
exec /u/team/infiloop.sh > /u/team/infiloopOutput.txt &
echo "Process was not running, started process $!"
fi

Related

Redirecting output in shell script from subprocess with simulated ctrl-c

I am working on a shell script, where it sets some parameters and calls a python script. Sometimes the python script hangs and when I press ctrl-c, it generates some error output. I am trying to write this to a file. When I execute the shell script and press ctrl-c, I get the output in the redirected file, but if I try to simulate the ctrl-c by sleeping for some time and killing the process, the output is not redirected to the file. I have used some examples from SO to do the sleep and terminate which works, but the output file doesn't have the error which I get from ctrl-c action manually.
I cannot change the python script that this script is executing, so I have to implement this in the calling script.
[ -z "$1" ] && echo "No environment argument supplied" && exit 1
. env_params.txt
. run_params.txt
echo "========================================================== RUN STARTED AT $B ==========================================================" >> $OUTFILE
echo " " >> $OUTFILE
export RUN_COMMAND="$PYTHON_SCRIPT_LOC/pyscript.py PARAM1=VALUE1 PARAM2=VALU2 PAram3=value3"
echo "Run command from test.sh $RUN_COMMAND" >> $OUTFILE
echo " " >> $OUTFILE
echo " " >> $OUTFILE
echo "========================================================== Running Python script ==========================================================" >> $OUTFILE
echo "Before python command"
###############################################
( python $RUN_COMMAND >> $OUTFILE 2>&1 ) & pid=$!
SLEEP_TIME=1m
echo "before sleep - sleeping for $SLEEP_TIME $pid"
( sleep $SLEEP_TIME && kill -HUP $pid ) 2>/dev/null & watcher=$!
if wait $pid 2>/dev/null; then
echo "after sleep - sleeping for $SLEEP_TIME $pid"
echo "your_command finished"
pkill -HUP -P $watcher
wait $watcher
else
echo "after sleep - sleeping for $SLEEP_TIME $pid"
echo "your_command interrupted"
fi
### also tried this - did not work either
### python $RUN_COMMAND >> $OUTFILE 2>&1 &; (pythonPID=$! ; sleep 1m ;kill -s 2 $pythonPID)
.
.
What changes do I need to make such that the output is written to the $OUTFILE when the process is killed in the script itself, rather than pressing ctrl-c on the terminal?
Probabelly you do not want to use SIGHUP (Hangup detected on controlling terminal or death of controlling process, but rather
SIGINT 2 Term Interrupt from keyboard
for more info read man 7 signal

How to write info to the file from bash script and see the result immediately?

I need help. I can't understand how I can write information to the file from bash script and see the result immediately.
For example:
#!/usr/bin/env bash
PID=$$
echo "PID is $PID"
echo $PID > my_script.pid
echo "Sleeping..."
sleep 5
echo "Finished"
PID number appears in console immediately, but in the file I see it after script finished.
I have Mac OS X Yosemite 10.10.3.
I tried a lot of stuff with flush buffering. NO result:(
Please, help!
Update.
My goal is to define if another instance of that script is still running. I decided to use pid file and condition:
PID=`cat $PID_FILE`
if ps -p $PID > /dev/null; then
echo "script already running"
exit 1
fi
Maybe there is a more efficient way?
You must be trying to read it too soon. To confirm that it's being written right away change the script to:
#!/usr/bin/env bash
PID=$$
echo "PID is $PID"
echo "$PID written to file." >> my_script.pid
echo "Sleeping..."
sleep 5
echo "Finished"
Then run:
touch my_script.pid
tail -F my_script.pid &
./my_script.sh
The tail -F command will run on the background and will output whatever is written to my_script.pid shortly after it's written. The delay you see is on tail, once echo returns it is written.
Sorry for misunderstanding. Actually it works fine. The problem in GUI tool (PyCharm) where I checked out file modification. It has interesting delay.
So when I check out previous PID from the same script it works fine:)
Thanks a lot fernan for help;)

Shell script: How to restart a process (with pipe) if it dies

I currently use the technique described in How do I write a bash script to restart a process if it dies? by lhunath in order to restart a dead process.
until myserver; do
echo "Server 'myserver' crashed with exit code $?. Respawning.." >&2
sleep 1
done
But rather than just invoking the process myserver, I would like to invoke such a thing:
myserver 2>&1 | /usr/bin/logger -p local0.info &
How to use the first technique with a process with pipe?
The until loop itself can be piped into logger:
until myserver 2>&1; do
echo "..."
sleep 1
done | /usr/bin/logger -p local0.info &
since myserver inherits its standard output and error from the loop (which inherits from the shell).
You can use the PIPESTATUS variable to get the exit code from a specific command in a pipeline:
while :; do
myserver 2>&1 | /usr/bin/logger -p local0.info
if [[ ${PIPESTATUS[0]} != 0 ]]
then echo "Server 'myserver' crashed with exit code ${PIPESTATUS[0]}. Respawning.." >&2
sleep 1
else break
fi
done

send signal between scripts (bash)

I've a little problem, probably it's a stupid question, but I started learning bash about a week ago...
I have 2 script, a.sh and b.sh. I need to make both running constantly. b.sh should waits for a signal from a.sh
(I'm trying to explain:
a.sh and b.sh run --> a.sh sends a signal to b.sh -> b.sh traps signal, does something --> a.sh does something else and then sends another signal --> b.sh traps signal, does something --> etc.)
This is what I've tried:
a.sh:
#!/bin/bash
./b.sh &;
bpid=$!;
# do something.....
while true
do
#do something....
if [ condition ]
then
kill -SIGUSR1 $bpid;
fi
done
b.sh:
#!/bin/bash
while true
do
trap "echo I'm here;" SIGUSR1;
done
When I run a.sh I get no output from b.sh, even if I redirect the standard output to a file...
However, when I run b.sh in background from my bash shell, it seems to answer to my SIGUSR1 (sent with the same command, directly from shell) (I'm getting the right output)
What I'm missing?
EDIT:
this is a simple example that I'm trying to run:
a.sh:
#!/bin/bash
./b.sh &
lastpid=$!;
if [ "$1" == "something" ]
then
kill -SIGUSR1 $lastpid;
fi
b.sh:
#!/bin/bash
trap "echo testlog 1>temp" SIGUSR1;
while true
do
wait
done
I can't get the file "temp" when running a.sh.
However if I execute ./b.sh & and then kill -SIGUSR1 PIDOFB manually, everything working fine...
One of the possible solutions would be the next one (perhaps, it's dirty one, but it works):
a.sh:
#!/bin/bash
BPIDFILE=b.pid
echo "a.sh: started"
echo "a.sh: starting b.sh.."
./b.sh &
sleep 1
BPID=`cat $BPIDFILE`
echo "a.sh: ok; b.sh pid: $BPID"
if [ "$1" == "something" ]; then
kill -SIGUSR1 $BPID
fi
# cleaning up..
rm $BPIDFILE
echo "a.sh: quitting"
b.sh:
#!/bin/bash
BPIDFILE=b.pid
trap 'echo "got SIGUSR1" > b.log; echo "b.sh: quitting"; exit 0' SIGUSR1
echo "b.sh: started"
echo "b.sh: writing my PID to $BPIDFILE"
echo $$ > $BPIDFILE
while true; do
sleep 3
done
The idea is to simply write down a PID value from within a b (background) script and read it from the a (main) script.

Bash, CTRL+C in eval not interrupting the main script

In my bash script, I'm running an external command that's stored in $cmd variable. (It could be anything, even some simple bash oneliner.)
If ctrl+C is pressed while running the script, I want it to kill the currently running $cmd but it should still continue running the main script. However, I would like to preserve the option to kill the main script with ctrl+C when the main script is running.
#!/bin/bash
cmd='read -p "Ooook?" something; echo $something; sleep 4 '
while true; do
echo "running cmd.."
eval "$cmd" # ctrl-C now should terminate the eval and print "done cmd"
echo "done cmd"
sleep 5 # ctrl-C now should terminate the main script
done
Any idea how to do it some nice bash way?
Changes applied based on answers:
#! /bin/bash
cmd='read -p "Ooook1?" something; read -p "Oook2?" ; echo $something; sleep 4 '
while true; do
echo "running cmd.."
trap "echo Interrupted" INT
eval "($cmd)" # ctrl-C now should terminate the eval and print "done cmd"
trap - INT
echo "done cmd"
sleep 5 # ctrl-C now should terminate the main script
done
Now, pressing ctrl+C while "Ooook1?" read will break the eval only after that read is done. (it will interrupt just before "Oook2") However it will interrupt "sleep 4" instantly.
In both cases it will do the right thing - it will just interrupt the eval subshell, so we're almost there - just that weird read behaviour..
If you can afford having the eval part run in a subshell, "all" you need to do is trap SIGINT.
#! /bin/bash
cmd='read -p "Ooook1?" something; read -p "Oook2?" ; echo $something; sleep 4 '
while true; do
echo "running cmd.."
trap "echo Interrupted" INT
eval "($cmd)" # ctrl-C now should terminate the eval and print "done cmd"
trap - INT
echo "done cmd"
sleep 5 # ctrl-C now should terminate the main script
done
Don't know if that will fit your specific need though.
$ ./t.sh
running cmd..
Ooook1?^CInterrupted
done cmd
^C
$ ./t.sh
running cmd..
Ooook1?qsdqs^CInterrupted
done cmd
^C
$ ./t.sh
running cmd..
Ooook1?qsd
Oook2?^CInterrupted
done cmd
^C
$
GNU bash, version 4.1.9(2)-release (x86_64-pc-linux-gnu)
You can determine whether the sleep command exited abnormally by examining the last exit status echo $?. A non-zero status probably indicates Ctrl-C.
No, read is not an external command, it is internal builtin bash command being executed in the same process as the other instructions. So at Ctrl-C all the process will be killed.
P.S.
Yes. you can execute command in subshell. Something like this
#!/bin/bash
cmd='trap - INT; echo $$; read -p "Ooook?" something; echo $something; sleep 4 '
echo $$
while true; do
echo "$cmd" > tmpfile
echo "running cmd.."
trap "" INT
bash tmpfile
rm tmpfile
trap - INT
echo "done cmd"
sleep 5 # ctrl-C now should terminate the main script
done

Resources