I wrote a shell.nix file to build the development environment for one of my projects. I'm using a shellHook to ensure a postgresql server is started when you drop into the nix-shell.

The shellHook is essentially:

export PGDATA=$PWD/nix/pgdata

pg_ctl start --silent --log $PWD/log/pg.log

Despite the fact that pg_ctl starts a server in the background, if I type Ctrl-C in the shell, the server shuts down. If I set up the same scenario outside of nix-shell, this does not happen.

I'm new to strace, but it looks to me like the postgresql process is receiving SIGINT when I type Ctrl-C in my terminal:

$ strace -p $postgres_pid
strace: Process 20546 attached
select(6, [3 4 5], NULL, NULL, {tv_sec=51, tv_usec=289149}) = ? ERESTARTNOHAND (To be restarted if no handler)
--- SIGINT {si_signo=SIGINT, si_code=SI_KERNEL} ---
write(2, "LOG:  received fast shutdown req"..., 37) = 37
kill(20550, SIGTERM)                    = 0

The postgresql process is attached to the same controlling terminal (pts/12) as my nix-shell process (though this is also true when I run it outside of nix-shell):

$ ps -p ${postgres_pid},${nixshell_pid} -o pid,ppid,wchan,tty,cmd
14608 18292 core_s pts/12   bash --rcfile /tmp/nix-shell-14608-0/rc
16355     1 core_s pts/12   /nix/store/xxxxxx-postgresql-9.6.8/bin/postgres

What's a good next step in debugging this? Should I read up on process groups?

Update: Trying a tip from another question, I found that this fixes the problem:

set -m
pg_ctl start --silent --log $PWD/log/pg.log

The weird thing is, according to $-, the m option was already set. Running echo $- produces imBH both before and after the set -m.

I noticed that in my interactive shells (whether nix-shell or not), $- is imBHs. The s is not present in the shellHook context, and I can't find an explanation of its meaning in the docs for Bash's set builtin. This may not be related though...

2 Answers 2


The manual says

start mode launches a new server. ... On Unix-like systems, by default, the server's standard output and standard error are sent to pg_ctl's standard output (not standard error). The standard output of pg_ctl should then be redirected to a file or piped to another process such as a log rotating program like rotatelogs; otherwise postgres will write its output to the controlling terminal (from the background) and will not leave the shell's process group. ...Use of either -l or output redirection is recommended.

It seems you need to redirect the output to detatch pg_ctl from the shell.

  • I'm using the -l option (--log), which supposedly will work as well. I tried using redirection instead (pg_ctl start --silent > $PWD/log/pg.log), but I get the same results. I also tried redirecting stderr as well (2>&1), still no difference.
    – ivan
    Aug 7, 2018 at 11:55
  • I would consider that a bug in pg_ctl. You may try nohup,
    – RalfFriedl
    Aug 7, 2018 at 16:58

It seems the problem was that the postgresql server was running as part of the same process group as the shell that launched it via pg_ctl. Typing propagated a SIGINT to all processes in the group.

One way to fix this is to launch postgresql in its own session using setsid.

setsid pg_ctl start --silent --log $PWD/log/pg.log

That said, I still don't know why this only happens in the context of shellHook.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .