1

I'm modifying an old script and for some reason it uses a subshell. I'm not sure if maybe the subshell is what's tripping me up. What I really want is to start a service and capture all of STDOUT and STDERR to a file as well as it's PID. Additionally, however I want some debug information in the log file. Consider the script below (startFoo.sh):

#!/bin/bash
VARIABLE=$(something_dynamic)
echo "Some output"
(
   # Enable debugging
   set -x
   foo -argument1=bar \
      -argument2=$VARIABLE

   # Disable debugging
   set +x

) > /tmp/foo_service.log 2>&1 &
OUTER_PID=$!
echo $OUTER_PID > foo.pid

This seems to work in that I'm capturing most of the output to the log as well as the PID, but for some reason not all of the output is redirected. When I run the script, I see this in my terminal:

[me@home ~]$ sudo startFoo.sh
Some output
[me@home ~]$ + foo -argument1=bar -argument2=value

How can I squash the output in my prompt that says [me@home ~]$ + foo...?

Note, this question may be related to another question: redirect all output in a bash script when using set -x, however my specific usage is different.

UPDATE: My script now looks like this, but something is still not quite right:

#!/bin/bash
VARIABLE=$(something_dynamic)
echo "Some output"
(
   # Enable debugging
   set -x
   foo -argument1=bar \
      -argument2=$VARIABLE

   # Disable debugging
   set +x

) > /tmp/foo_service.log 2>&1 &
PID=$!
echo $PID > foo.pid

However, when I do this, the PID file contains the PID for startFoo.sh, not the actual invocation of foo which is what I really want to capture and be able to kill. Ideally I could kill both startFoo.sh and foo with one PID, but I'm not sure how to do that. How is this normally handled?

UPDATE: The solution (thanks to a conversation with @konsolebox) is below:

#!/bin/bash 
VARIABLE=$(something_dynamic) 
echo "Some output" 
{ 
   # Enable debugging 
   set -x 
   foo -argument1=bar \ 
      -argument2="$VARIABLE" &
   PID=$! 
   echo $PID > foo.pid 

   # Disable debugging 
   set +x
} > /tmp/foo_service.log 2>&1
Community
  • 1
  • 1
blong
  • 2,815
  • 8
  • 44
  • 110

1 Answers1

3

Change 2>&1> /tmp/foo_service.log to >/tmp/foo_service.log 2>&1.

You should first redirect fd 1 to the file, then let fd 2 duplicate it. What you're doing on the former is that you first redirect fd 2 to 1 which only copies the default stdout, not the file's fd which is opened after it.

konsolebox
  • 72,135
  • 12
  • 99
  • 105
  • Thanks @konsolebox, I think it's working, but I'm not entirely sure I understand the solution. Are you saying that there are two separate redirections happening here? What do you mean by "_let fd 2 duplicate it_". Meaning duplicate the instruction to redirect output? – blong Jul 30 '14 at 15:13
  • @b.long Yes there are two separate redirections happening. Basically you just manipulate the file descriptors to get both handling same stream or same file. It's not easy to explain but you can consider reading more about it [here](http://www.tldp.org/LDP/abs/html/io-redirection.html) and [here](http://stackoverflow.com/questions/3385201/confused-about-stdin-stdout-and-stderr). Wikipedia may also give some [info](http://en.wikipedia.org/wiki/Standard_streams). – konsolebox Jul 30 '14 at 15:27
  • Interesting, ok. In further testing, I ended up modifying the script. Perhaps my instinct is wrong on solving this problem. Since `foo` is long running, I believe it needs to be backgrounded so that `startFoo.sh` will return the user to the command prompt, but now I seem to be capturing the wrong PID. I've updated my question. – blong Jul 30 '14 at 15:50
  • @b.long Is foo the only command you run before and after set -x/set +x? And is foo a script or binary? – konsolebox Jul 30 '14 at 15:58
  • Yes, `foo` is the only command run between `set -x` and `set +x`, but I do have a conditional before `set -x` and some additional output that I'd like directed into `/tmp/foo_service.log` – blong Jul 30 '14 at 16:01
  • I did try using `{ }` for grouping rather than `( )`, but this doesn't change the fact that the wrong PID is captured now. Notably, if the PID for `startFoo` is 2222, `foo` will be 2223. – blong Jul 30 '14 at 16:03
  • Since we continued our discussion in the chat, @konsolebox walked me through a solution. I'll post it as an update to my question. – blong Jul 30 '14 at 16:26