3

I was trying to run the command given below

cat numbers.txt | sort < words.txt

The above command has a pipe from cat command feeding to input stream of sort command. But at the same time, input stream of the sort command is also redirected to the words.txt file. On running the command i found that the data from words.txt is sorted by the sort command and displayed back in terminal.

I don't understand how the shell processes the piping and redirection in such a case. Is it possible for one command to accept input stream from two different sources. My thoughts on how it worked internally was that, since redirection and piping are handled from left to right along the command, first the output stream of the cat command will be fed as the input stream for sort command. But since sort command is provided with another input stream redirection after this pipe, the input stream of sort command will be then be connected to words.txt. So when the command executes, data from words.txt would only reach sort command.

Also why isn't the following command not running.I have changed the redirection by overwriting to redirection by appending.

cat numbers.txt | sort << words.txt

There is a question partly similar to this, but i couldn't exactly understand how the pipe and redirection was handled by the shell.

1

2 Answers 2

5

Redirections are processed from left to right, and in Bash, after pipelines (in fact, in any POSIX shell). In

cat numbers.txt | sort < words.txt

the shell first sets up sort’s (future) standard input to be the pipe from cat, but then when it processes < words.txt, changes it to read words.txt.

<< starts a heredoc:

cat numbers.txt | sort << words.txt

will sit waiting for a line saying “words.txt” (since that is specified as the end-of-input marker in your command). See What are the shell's control and redirection operators?

2
  • @Vilinkameni but you were using it to prove “the command cat in the above examples will run completely, just its output will be discarded”, and it doesn’t. Commented Sep 22, 2023 at 15:59
  • What I (eventually, after a discussion which is now deleted, where you provided some counterexamples to my more general initial claim) wanted is to include the case if command1 is a script. Generally, not all of the commands in it will be terminated in command1 | command2 <somefile. Under the effects of set +o errexit, only those commands from command1 writing to stdout will be terminated due to receiving SIGPIPE. Commented Sep 22, 2023 at 16:46
3

Is it possible for one command to accept input stream from two different sources.

No; an input stream is literally just a file descriptor that someone else hands to you. Just as you only have one file in a file, there's no way to merge multiple streams.

cat numbers.txt | sort < words.txt

By the way, cat is short for concatenate; its job literally is to concatenate all files specified on its command line to its output stream:

cat numbers.txt words.txt | sort 

works. Of course, sort itself can also sort multiple files, so sort numbers.txt words.txt would work just as well.

But I guess the question is more general:
If I have multiple files and stream, how do I concatenate them into one output?

Well, modern shells do have you covered (at least bash and zsh do):

cat file1 <(some program that generates output) <(echo "foo bar") file2 | sort

These shells have <(…), i.e. "generate a temporary pipe that gets passed as input file name". Of course, there's also very simple subshell methods:

( cat file1; some program that generates output; echo "foo bar"; cat file2 ) | sort

has the same effect. (There are differences in the parallelism of execution; cat <(sleep 2; echo hello) <(sleep 2; echo world) takes 2 seconds to execute in total; (sleep 2; echo hello; sleep 2; echo world) takes 4 seconds.)

2
  • 1
    I actually did not want to concatenate the two files and feed them to sort. I used two files having different data so that i would understand which input stream was ultimately used by the sort command (pipe vs redirection). I guess I didn't phrase the question properly. My bad. But thank you for answer. I thought merging streams was something possible. Commented Sep 22, 2023 at 12:49
  • In POSIX sh, FIFOs can be used for a similar effect to <(), Instead of sort <(prog1) <(prog2) one would write mkfifo prog1f prog2f; prog1 >prog1f & prog2 >prog2f & sort prog1f prog2f; rm prog1f prog2f Commented Sep 22, 2023 at 14:59

You must log in to answer this question.

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