0

I would like to have a function in bash, that starts a program in the background, determines the PID of that program and also pipe's its output to sed. I know how to do either one of them separately, but not how to achieve all of them at once.

What I have so far is this:

# Start a program in the background
#
# Arguments:
#  1  - Variable in which to "write" the PID
#  2  - App to execute
#  3  - Arguments to app
#
function start_program_in_background() {

    RC=$1; shift

    # Start program in background and determine PID
    BIN=$1; shift
    ( $BIN $@ & echo $! >&3 ) 3>PID | stdbuf -o0 sed -e 's/a/b/' &
    # ALTERNATIVE $BIN $@ > >( sed .. ) &

    # Write PID to variable given as argument 1
    PID=$(<PID)
    # when using ALTERNATIVEPID=$!
    eval "$RC=$PID"

    echo "$BIN ---PID---> $PID"
}

The way I extract the PID is inspired by [1]. There is a second variant in the comments. Both of them show the output of the background processes when executing a script that starts programs using above function, but there is no output when I pipe

[1] How to get the PID of a process that is piped to another process in Bash?

Any ideas?

Community
  • 1
  • 1
Stefan
  • 1,757
  • 1
  • 10
  • 8
  • 1
    Unrelated to the question, but you should put `$@` in double quotes to get proper re-quoting of the result. – Barmar Dec 07 '16 at 20:52
  • What does the caller do with the PID? If it kills the process, it might kill it before it has a chance to send anything to `sed`. – Barmar Dec 07 '16 at 20:58
  • Right now, I simply put a `sleep 10` after and then kill it, yes. But there should be plenty of time for the process to output things. I also tried using `stdbuf -i0` to make sure the problem is not related to buffering. – Stefan Dec 07 '16 at 21:07
  • Thanks for the hints with the double quotes! – Stefan Dec 07 '16 at 21:08
  • You may need to use `stdbuf -o0` on `$BIN` to prevent its output to the pipe from being buffered. – Barmar Dec 07 '16 at 21:10
  • As an aside, you don't need to use `eval`; `read "$RC" < PID` will populate the desired variable. – chepner Dec 07 '16 at 21:30

1 Answers1

1

Solution:

I came up with this myself thanks to some of the helpful comments. In order to being able to mark as solved, I'm posting the working solution here.

# Start a program in the background
#
# Arguments:
#  1  - Variable in which to "write" the PID
#  2  - App to execute
#  3  - Arguments to app
#
function start_program_in_background() {

    RC=$1; shift

    # Create a temporary file to store the PID
    FPID=$(mktemp)

    # Start program in background and determine PID
    BIN=$1; shift
    APP=$(basename $BIN)
    ( stdbuf -o0 $BIN $@ 2>&1 & echo $! >&3 ) 3>$FPID | \
            stdbuf -i0 -o0 sed -e "s/^/$APP: /" |\
            stdbuf -i0 -o0 tee /tmp/log_${APP} &

    # Need to sleep a bit to make sure PID is available in file
    sleep 1

    # Write PID to variable given as argument 1
    PID=$(<$FPID)
    eval "$RC=$PID"

    rm $FPID # Remove temporary file holding PID
}
Stefan
  • 1,757
  • 1
  • 10
  • 8