So I have a bash command using process substitution in an exec line that stopped working recently, and it boils down to this example:

Contents of script.sh:

ls -l "$1" >/tmp/out  
echo "SUCCESS" > "$1"

This works, putting "SUCCESS" into log:

rm -f log; ./script.sh >(cat >log)

Using tail also works:

rm -f log; ./script.sh >(tail >log)

Using exec with cat works:

rm -f log; exec ./script.sh >(cat >log)

But.. exec with tail does NOT work:

rm -f log; exec ./script.sh >(tail >log)

In all cases, the contents of /tmp/out look okay, looking something like:

l-wx------ 1 user user 64 Oct 14 10:55 /dev/fd/63 -> pipe:[158518]

Why does cat work but not tail or head? This was working at sometime in the past.. is this a bash feature change or bug regression..?

bash --version: GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)

1 Answer 1


So using strace on substituted process revealed that tail and head were getting a SIGHUP from the kernel before they had a chance to write. A simple workaround is to add nohup to the substitution:

rm -f log; exec ./script.sh >(nohup tail >log)

I think I understand why this fails with exec. IIUC, >(tail >log) creates a child process of the current bash process. However when using exec, it now becomes a child process of script.sh. When script.sh exits, the kernel sends SIGHUP to all child processes.

Still not sure why this used to work, perhaps in newer kernel versions it is faster/more aggressive about sending its SIGHUPs.

You must log in to answer this question.

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