58

Assuming file2 already exists, the command

> file1 < file2 cat

appears to be copying the content of file2 to file1.

But I cannot understand this structure.

I understand that "Nothing" is being directed to file1, (creating or erasing its content). Then the content of file2 is being directed to file1.

Why is cat after file2? how does it know to cat file2 if the operands are not in the correct order?

  • 10
    What "correct order"? Can you provide a link to some resource / learning material where a "correct order" is described? – Lightness Races in Orbit Apr 5 '17 at 17:35
  • 7
    When asking questions like this, you should specify the shell; different ones have different edge cases, especially around redirection. – chrylis Apr 5 '17 at 23:26
112

Before the shell executes the cat command on the command line, it looks for redirections.

There are two redirections:

  1. >file1 This will make the command's standard output go to file1.
  2. <file2 This will make the command's standard input come from file2.

The fact that these redirections are placed in a wonky location on the command line doesn't matter.

$ cat <file2 >file1

is the same as

$ <file2 cat >file1

which is the same as

$ <file2 >file1 cat

etc.¹

Note that the cat utility in all of these instances is executed without any command line arguments. The redirections are not operands to the cat command, they are instructions to the shell to set up redirections into and out of the command (connecting its standard input and output to files). The shell sets up the redirections before invoking the command.

The difference between cat file and cat <file (or, if you will, <file cat) is that in the first case, the cat utility itself is opening the file, which is given as an operand on the command line, for reading, while in the second case, the shell will open the file and connect cat's input stream to it². In the second case, cat will notice it wasn't given a file operand and will automatically switch to reading from its standard input. This is a feature of cat, and of some other utilities, not something that all utilities do.

cat will also read from its standard input if it's given the operand -. Again, this is special only to cat and to some other utilities (i.e. nothing that the shell does). To use cat on a file in the current directory whose name is -, add a path to the filename, such as ./-.

¹ The order of the redirections is still important under some circumstances; With cat <file2 >file1, for example, file1 will not be truncated if file2 is inaccessible (the redirections are parsed from left to right). The relative placement of the word cat is however still arbitrary and won't influence this.

² See also the question "cat gives different error when opening non-existing file".


The fact that the shell sets up the redirections before even executing the command on the command line is why things like these fail and you end up with an empty output file:

$ sort file >file

Here, the shell will truncate (empty) the file file before executing sort file and connecting sort's standard output to the file. The sort utility will then open file and sort its contents (which is nothing). The result (nothing) is passed through the standard output stream to file.

The remedy in this particular case (for sorting a file "in-place") is

$ sort -o file file

or

$ sort file >file.sorted && mv file.sorted file

which is more or less what sort does when using the -o file to specify the output file name.


Just to back up the statement that the redirections may precede the actual name of the utility on the command line:

A "simple command" is a sequence of optional variable assignments and redirections, in any sequence, optionally followed by words and redirections, terminated by a control operator. [ref: POSIX Shell Command Language 2.9.1 Simple Commands]

And also about the redirection not being part of the operands of the utility:

The optional number, redirection operator, and word shall not appear in the arguments provided to the command to be executed (if any). [ref: POSIX Shell Command Language 2.7 Redirection]

  • 14
    @Steve The freedom to move redirections around can be used to make some commands clearer, like a pipeline with input redirection at the beginning <in foo | bar >out puts everything in logical order. I'm also fond if echo >&2 Something bad happened for error output from shell scripts. But >out <in cat is just obfuscation – Wumpus Q. Wumbley Apr 5 '17 at 14:42
  • 2
    How might sort file >file be correctly accomplished? – seth10 Apr 5 '17 at 16:02
  • 11
    @setht With sort -o file file. – Kusalananda Apr 5 '17 at 16:03
  • 6
    Great answer. Note that order matters. < file1 > file2 cat would be better than > file2 < file1 cat as that would avoid file2 being truncated if file1 can't be opened. – Stéphane Chazelas Apr 7 '17 at 8:14
  • 3
    Something to be aware of: when linking to POSIX with HTML fragments, it's better to specify the exact edition (like pubs.opengroup.org/onlinepubs/9699919799.2016edition) as fragments have been known to change between editions of a same revision of the spec (a lot of links in answers on this site including of mine are now wrong as the fragments point in the wrong place after the 2016 edition has been released). – Stéphane Chazelas Apr 7 '17 at 8:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.