9

I have a script to process records in some files, it usually takes 1-2 hours. When it's running, it prints a progress of number of records processed.

Now, what I want to do is: when it's running with nohup, I don't want it to print the progress; it should print progress only when it run manually.

My question is how do I know if a bash script is running with nohup?

Suppose the command is nohup myscript.sh &. In the script, how do I get the nohup from command line? I tried to use $0, but it gives myscript.sh.

phs
  • 10,687
  • 4
  • 58
  • 84
Gary
  • 4,495
  • 13
  • 36
  • 49

5 Answers5

9

Checking for file redirections is not robust, since nohup can be (and often is) used in scripts where stdin, stdout and/or stderr are already explicitly redirected.

Aside from these redirections, the only thing nohup does is ignore the SIGHUP signal (thanks to Blrfl for the link.)

So, really what we're asking for is a way to detect if SIGHUP is being ignored. In linux, the signal ignore mask is exposed in /proc/$PID/status, in the least-significant bit of the SigIgn hex string.

Provided we know the pid of the bash script we want to check, we can use egrep. Here I see if the current shell is ignoring SIGHUP (i.e. is "nohuppy"):

$ egrep -q "SigIgn:\s.{15}[13579bdf]" /proc/$$/status && echo nohuppy || echo normal
normal
$ nohup bash -c 'egrep -q "SigIgn:\s.{15}[13579bdf]" /proc/$$/status && echo nohuppy || echo normal'; cat nohup.out
nohup: ignoring input and appending output to `nohup.out'
nohuppy
phs
  • 10,687
  • 4
  • 58
  • 84
1

You could check if STDOUT is associated with a terminal:

[ -t 1 ]
lukuluku
  • 4,344
  • 3
  • 30
  • 35
  • 4
    Note that this check the terminal, not if it is running under nohup. If you run `myscript.sh > out.txt` this check will fail too. (I didn't downvote you) – johndodo Sep 03 '15 at 10:00
1

One way, but not really portable would be to do a readlink on /proc/$$/fd/1 and test if it ends with nohup.out.

Assuming you are on the pts0 terminal (not really relevant, just to be able to show the result):

#!/bin/bash

if [[ $(readlink /proc/$$/fd/1) =~ nohup.out$ ]]; then
    echo "Running under hup" >> /dev/pts/0
fi

But the traditional approach to such problems is to test if the output is a terminal:

[ -t 1 ]
Sorin
  • 5,201
  • 2
  • 18
  • 45
1

You can either check if the parent pid is 1:

if [ $PPID -eq 1 ] ; then
    echo "Parent pid=1  (runing via nohup)" 
else
    echo "Parent pid<>1 (NOT running via nohup)"                                             
fi

or if your script ignores the SIGHUP signal (see https://stackoverflow.com/a/35638712/1011025):

if egrep -q "SigIgn:\s.{15}[13579bdf]" /proc/$$/status ; then
    echo "Ignores SIGHUP (runing via nohup)" 
else
    echo "Doesn't ignore SIGHUP (NOT running via nohup)"                                             
fi
ndemou
  • 4,691
  • 2
  • 30
  • 33
0

Thank you guys. Check STDOUT is a good idea. I just find another way to do it. That is to test tty. test tty -s check its return code. If it's 0 , then it's running on a terminal; if it's 1 then it's running with nohup.

Gary
  • 4,495
  • 13
  • 36
  • 49
  • 3
    actually, you are doing the exact same thing tty -s checks if stdout is a terminal (see: http://ss64.com/bash/tty.html) and -t 1 is the same (see: http://www.gnu.org/software/bash/manual/bashref.html#Bash-Conditional-Expressions) – Sorin Mar 05 '13 at 21:40