Simple Linux pipeline
dup2 handles equal file descriptors very nicely. There is no need to test for in != 0 etc.
On the other hand, you must check the return values, especially those of the system calls, and give a proper diagnostics when necessary.
An idea of executing the last pipeline component inside a master process is dubious. You lose the control over children's lifecycle. I recommend to run each component in its own process, and wait for all of them.

An i &lt; n - 1 loop terminating condition looks alarming. It takes some mental effort to understand what you are after. You may try to heal it with the comment, but most likely you should treat all pipeline components equally.
Keep in mind that some commands (cd being most prominent) must be builtins. Spawning a shell for them would be a design mistake.