-1

I have written shell script which invokes the python code. The python code is executed via nohup.

When the python code is executed from terminal as is nohup stdbuf -oL python3 -u pid_ watch.py > log.txt 2>&1 & it returns output as [1] 2128. It returns the process id.

But when same executed from shell script it return empty string. Following is the code:

#!/bin/bash

#export arguments=${@}

filepath=""
username=""
while getopts 'v:u:' OPT; do
case "$OPT" in
        v) filepath=$OPTARG;;
        u) username=$OPTARG;;
esac
done

program_log="$(dirname "$filepath")/$(basename "$filepath" .py)_"$username".log"
output=`nohup stdbuf -oL python3 -u "$filepath" > "$program_log" 2>&1 &`
echo "${output}"

Here output is empty string. But when ps -ef is done it shows a python process it started with that program.

How can I resolve this to get the process id from nohup in output variable?

  • You can't background a process _and also_ capture its output. Either the backgrounding is meaningless because you're actually blocking on reading the output so it's practically still in the foreground, or the data is redirected away to allow it to be truly backgrounded so you can't capture any output. – Charles Duffy Feb 22 '23 at 17:21
  • So you can use `nohup yourprogram &`, **or** you can use `output=$(...)`. You can't do both at once. Pick one or the other. – Charles Duffy Feb 22 '23 at 17:21
  • (also, `nohup` itself is basically meaningless/useless; `nohup yourprogram &` is basically identical to `yourprogram >nohup.out 2>&1 – Charles Duffy Feb 22 '23 at 17:23
  • Anyhow -- why do you think `nohup` is doing anything of any importance or value here? If you describe why you think you need nohup, that'll put you in a much better place to get an answer. – Charles Duffy Feb 22 '23 at 17:28
  • I will submit the python program to execute in background instead of waiting for it to complete. That's Why I am using `nohup` – puneet Shah Feb 23 '23 at 04:09
  • But how can you collect a program's output without waiting for it to complete? If it's not complete, the output isn't finished yet. – Charles Duffy Feb 23 '23 at 15:48
  • When you run `nohup stdbuf -oL python3 -u pid_ watch.py > log.txt 2>&1 &` in an interactive shell, the printed `[1] 2128` **is not part of that program's output at all**. It's not written to stdout by nohup, or stdbuf, or python. Instead, it's written _by the shell itself_, and can't be captured with a command substitution. – Charles Duffy Feb 23 '23 at 15:50

2 Answers2

0

By definition, nohup will trap all output, stdout and stderr, in nohup.out.

You will need to stdbuf with like this:

#!/bin/bash
echo $$ >$0.pid
...{your script logic}...

As it is, output will never get the PID. With the above, you can follow your nohup statement

nohup stdbuf -oL python3 -u "$filepath" > "$program_log" 2>&1 &

with

read PID <$0.pid
Eric Marceau
  • 1,601
  • 1
  • 8
  • 11
  • In nohup.out _if_ it was going to a TTY when nohup was invoked. If stdout is already going to a file, nohup does not redirect it. – Charles Duffy Feb 22 '23 at 17:19
  • @Charles Duffy, I tested on my end before posting my answer. nohup behaves as I described for my environment. GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu) // Linux 5.4.0-135-generic #152-Ubuntu SMP Wed Nov 23 20:19:22 UTC 2022 – Eric Marceau Feb 22 '23 at 20:21
  • I assume "your environment" is with stdout going to a TTY. That's typical, and the answer behaves as you describe in that case. I wasn't asserting that the answer is _wrong_, but rather that assertions it makes are only conditionally true. – Charles Duffy Feb 22 '23 at 20:34
  • I created a script to emulate the scenario presented by the OP. The description offered reflected that. I used the script as originally provided by the OP and it does not expose the stderr to the shell to be capture by the "output=..." statement. I tried adding "; echo $?" before the "&" and that is not allowed. Hence the approach recommended. – Eric Marceau Feb 22 '23 at 20:39
  • I did this to get the process id `pgrep -fn "$filepath" -u "$username"` – puneet Shah Feb 23 '23 at 04:07
0

nohup doesn't write the process ID to output at all. It's the shell (not nohup, or stdbuf, or python) that writes the content you see, but it's not going through stdout so it can't be captured with a command substitution; and it's not written at all in a shell without job control turned on, and these features are disabled by default in scripts.

To collect the PID of a program you started, just use $!

nohup stdbuf -oL python3 -u "$filepath" > "$program_log" 2>&1 & pid=$!

...will store the PID in the variable $pid.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441