How to make top run in background ? It needs to run and log the output. Not die or zombie up - linux

I am trying to make a script to log the top output to a file in the background for my embedded system. But as soon as I put it in background, it either exits or zombies up. What is the systems problem with running things in background ?
My script
TOP_LOG_FILE=top_log.txt
if [ -e $TOP_LOG_FILE ] ; then
rm $TOP_LOG_FILE
fi
while true
do
echo "##"`date`"##" >> $TOP_LOG_FILE
nohup top -n 1 >> $TOP_LOG_FILE
sleep 1
echo "##xxxxxxxxxxx##" >> $TOP_LOG_FILE
done
I am trying to execute it as
# nohup sh top_log.sh &
[4] 3051559
appending output to nohup.out
#
[4] + Stopped (tty output) nohup sh top_log.sh
and as
[5] 3121193
sh: top_log.sh: cannot execute - No such file or directory
[6] 3121194
#
[6] Done > /dev/null
[5] Done (126) top_log.sh
#
How do I actually get around this behavior?

top -n 1 -b
Tail that in a loop and append to file.
Wrap your loop in a script and launch it from terminal with &.

Related

nohup append the executed command at the top of the output file

Let's say that we invoke the nohup in the following way:
nohup foo.py -n 20 2>&1 &
This will write the output to the nohup.out.
How could we achieve to have the whole command nohup foo.py -n 20 2>&1 & sitting at the top of the nohup.out (or any other specified output file) after which the regular output of the executed command will be written to that file?
The reason for this is for purely debugging purpose as there will be thousands of commands like this executed and very often some of them will crash due to various reasons. It's like a basic report kept in a file with the executed command written at the top followed by the output of the executed command.
A straightforward alternative would be something like:
myNohup() {
(
set +m # disable job control
[[ -t 0 ]] && exec </dev/null # redirect stdin away from tty
[[ -t 1 ]] && exec >nohup.out # redirect stdout away from tty
[[ -t 2 ]] && exec 2>&1 # redirect stderr away from tty
set -x # enable trace logging of all commands run
"$#" # run our arguments as a command
) & disown -h "$!" # do not forward any HUP signal to the child process
}
To define a command we can test this with:
waitAndWrite() { sleep 5; echo "finished"; }
...and run:
myNohup waitAndWrite
...will return immediately and, after five seconds, leave the following in nohup.out:
+ waitAndWrite
+ sleep 5
+ echo finished
finished
If you only want to write the exact command run without the side effects of xtrace, replace the set -x with (assuming bash 5.0 or newer) printf '%s\n' "${*#Q}".
For older versions of bash, you might instead consider printf '%q ' "$#"; printf '\n'.
This does differ a little from what the question proposes:
Redirections and other shell directives are not logged by set -x. When you run nohup foo 2>&1 &, the 2>&1 is not passed as an argument to nohup; instead, it's something the shell does before nohup is started. Similarly, the & is not an argument but an instruction to the shell not to wait() for the subprocess to finish before going on to future commands.

Running a interactive command as a background process in shell script

I am facing an issue when I am trying to run a interactive command/app in the background of the shell script. I am trying to log the output of the command to a file. But I don't see that command logging anything to the file. Even executing the command in the bash also did not work as it gets suspended.
Sample script
#!/bin/bash
while true
do
./a.out > test &
PID=$!
sleep 20
kill -9 $PID
done
[#myprog]$ ./a.out &
[1] 3275
Program started
[1]+ Stopped ./a.out
[#myprog]$
You don't need to create a background process to redirect data. You can do the following, which will create a logfile actions.log which holds your every action.
#! /bin/bash
while read -p "action " act; do
echo $act
done > actions.log
exit 0
For you, this would be something like:
$ a.out > test.log
If you do want to have a background process, but need to input data:
$ function inter_child {
./inter.sh <<-EOF
a
b
c
d
EOF
sleep 10
}
$ inter_child &
$ wait
$ cat actions.log
a
b
c
d
If this doesn't answer your question, please be more specific why you need to create a child process and what's a.out is expecting. Hope this helps!
EDIT:
stdout and stderr are two different redirections.
Write stderr to file 2>: $ ./a.out 2> error.log
Redirect stderr to stdout 2>&1: $ ./a.out > log.log 2>&1

Running a script with top command in the background

I have a script that basically prints that output of top -n1 to a file every second
In its simplest form:
while [ 1 ] ; do
top -n1
sleep 1
done
If I run my secript like:
./my_script.sh > out.log
it runs fine
If I run it in the background:
./my_script.sh > out.log &
Then it give me Stopped(SIGTTOU) error. From other Q/As I found that top is trying to read from the stdin, and when run in the background there is no stdin.
How can I achieve logging of top into a file as a background task?
You need to write top to file, and that in a loop..
#!/bin/bash
while [ 1 ] ; do
top -b -n 1 > top.txt
sleep 1
done
or
#!/bin/bash
while :
do
top -b -n 1 > top.txt
sleep 1
done

How to kill a process by reading from pid file using bash script in Jenkins?

Inside Jenkins, I have to run 2 separate scripts: start.sh and stop.sh. These scripts are inside my application which is fetched from a SCM . They are inside same directory.
The start.sh script runs a process in the background using nohup, and writes the processId to save_pid.pid. This script works fine. It successfully starts my application.
Then inside stop.sh, I am trying to read the processId from save_pid.pid to delete the process. But,I am unable to delete the process and the application keeps running until I kill the process manually using: sudo kill {processId}.
Here are the approaches that I have tried so far inside stop.sh but none of these work:
kill $(cat /path/to/save_pid.pid)
kill `cat /path/to/save_pid.pid`
kill -9 $(cat /path/to/save_pid.pid)
kill -9 `cat /path/to/save_pid.pid`
pkill -F /path/to/save_pid.pid
I have also tried all of these steps with sudo as well. But, it just doesn't work. I have kept an echo statement inside stop.sh, which prints and then there is nothing.
What am I doing wrong here ?
UPDATE:
The nohup command that I am using inside start.sh is something like this:
nohup deploy_script > $WORKSPACE/app.log 2>&1 & echo $! > $WORKSPACE/save_pid.pid
Please Note:
In my case, the value written inside save_pid.pid is surprisingly
always less by 1 than the value of actual processId. !!!
I think the reason why this happens is because you are not getting the PID of the process that you are interested in, but the PID of the shell executing your command.
Look:
$ echo "/bin/sleep 10" > /tmp/foo
$ chmod +x /tmp/foo
$ nohup /tmp/foo & echo $!
[1] 26787
26787
nohup: ignoring input and appending output to 'nohup.out'
$ pgrep sleep
26789
So 'nohup' will exec the 'shell', the 'shell' will fork a second 'shell' to exec 'sleep' in, however I can only count two processes here, so I am unable to account for one created PID.
Note that, if you put the nohup and the pgrep on one line, then pgrep will apparently be started faster than the shell that 'exec's 'sleep' and thus pgrep will yield nothing, which somewhat confirms my theory:
$ nohup /tmp/foo & echo $! ; pgrep sleep
[2] 26899
nohup: ignoring input and appending output to 'nohup.out'
$
If you launch your process directly, then nohup will "exec" your process and thus keep the same PID for the process as nohup itself had (see http://sources.debian.net/src/coreutils/8.23-4/src/nohup.c/#L225):
$ nohup /bin/sleep 10 & echo "$!"; pgrep sleep
[1] 27130
27130
nohup: ignoring input and appending output to 'nohup.out'
27130
Also, if you 'exec' 'sleep' inside the script, then there's only one process that's created (as expected):
$ echo "exec /bin/sleep 10" > /tmp/foo
$ nohup /tmp/foo & echo "$!"; pgrep sleep
[1] 27309
27309
nohup: ignoring input and appending output to 'nohup.out'
27309
Thus, according to my theory, if you'd 'exec' your process inside the script, then you'd be getting the correct PID.

Bash script to re-launch program in case of failure error

In linux (I use a Ubuntu), I run a (ruby) program that continually runs all day long. My job is to monitor to see if the program fails and if so, re-launch the program. This consists up simply hitting 'Up' for last command and 'Enter'. Simple enough.
There has to be a way to write a bash script to monitor my program if its stops working and to re-launch it automatically.
How would I go about doing this?
A bonus is to be able to save the output of the program when it errors.
What you could do:
#!/bin/bash
LOGFILE="some_file.log"
LAUNCH="your_program"
while :
do
echo "New launch at `date`" >> "${LOGFILE}"
${LAUNCH} >> "${LOGFILE}" 2>&1 &
wait
done
Another way is to periodicaly check the PID:
#!/bin/bash
LOGFILE="some_file.log"
LAUNCH="your_program"
PID=""
CHECK=""
while :
do
if [ -n "${PID}" ]; then
CHECK=`ps -o pid:1= -p "${PID}"`
fi
# If PID does not exist anymore, launch again
if [ -z "${CHECK}" ]; then
echo "New launch at `date`" >> "${LOGFILE}"
# Launch command and keep track of the PID
${LAUNCH} >> "${LOGFILE}" 2>&1 &
PID=$!
fi
sleep 2
done
Infinite loop:
while true; do
your_program >> /path/to/error.log 2>&1
done

Resources