Você não pode "enviar EOF". Simplesmente não há "caractere EOF" que passaria pelo pipe.
Normalmente, os programas Linux lêem a partir de um descritor de arquivo usando read (2) no modo de bloqueio, preenchendo um buffer com os dados recebidos e retornando a quantidade de caracteres lidos. Quando read retorna 0, ou seja, 0 bytes foram lidos, a maioria dos programas interpreta isso como fim de arquivo.
Um programa pode liberar seu lado do pipe antes que o buffer esteja cheio, usando fsync (2). Nesse caso, o read do leitor retornaria imediatamente, mesmo se o buffer estivesse vazio, retornando 0 como a quantidade de bytes de leitura.
Você pode observar isso executando cat , digitando alguns caracteres (não retorna) e pressionando Ctrl-D (o que causa um flush no terminal). Nesse momento, cat imprimirá os caracteres digitados. Pressione Ctrl-D novamente, e cat read retornará 0 bytes, fazendo com que cat considere ter alcançado o final do arquivo. Como o buffer de linha é usado, cat também imprime sua entrada quando você pressiona Return.