Does `echo -n | ...` send an EOF to the pipe?

There is no EOF that is represented as data in a file or stream. It is merely a status associated with the file descriptor.

When the echo terminates (which will be almost immediately), the write end of the pipe is closed.

The next time sth reads (assuming it has read all data previously written to the file) the pipe status changes to EOF and the read issued by sth returns with the EOF condition. The process can continue with any processing it requires, it just cannot read any more from the pipe.

There's no EOF to send or receive.

EOF is just an api fiction that only exists in the stdio library. It's a status flag of a FILE* stdio input stream which is usually set after a read(2) system call on the underlying file descriptor has returned 0. And a macro for -1 which is the value returned by fgetc(3) and similar functions when called on a input stream with its EOF flag on.

While you can speak metaphorically of "sending an EOF" as "indirectly cause some future read(2) to return 0", that's quite sloppy, and will create the false impression that EOF is some kind of inline signal, or a status of the underlying file descriptor or device that could be set from the other end.

On a pipe, read(2) will return 0 if

  1. the pipe buffer is empty, and
  2. there's no open handle to its writing end

Both conditions are transient, which is consistent with the way the EOF conditions are transient on regular files or terminals.

In particular, notice that on Linux, all pipes are effectively named pipes: as long as a process still has an open handle to the reading end of a pipe, you can also revive its writing end by opening the pipe in write mode via /proc/<pid>/fd/<fd>. While that may not be that easy on other systems, having a sticky EOF on an "anonymous" pipe is not part of its interface.

Yes. A program that reads from a pipe sees an end-of-file on the pipe when the program that writes to the pipe closes the writing end. More precisely, the end-of-file event happens when the last file descriptor that was open on the pipe gets closed. Ways to close a file descriptor include explicit closing and a process exiting.

Here there's just one process writing to the pipe and running echo -n, which depending on the shell either writes -n and a newline, or nothing. When that process has finished writing and exits, the writing end of the pipe is closed, so sth sees EOF on the pipe. (It's also possible that the shell runs the left-hand side of the pipe without forking, in which case the shell closes the pipe explicitly when it's done writing: this optimization doesn't make any difference to the right-hand side of the pipe.)