4

In many Linux books is written that 'redirection is executed before a command'. Let's consider:

$ cat bar
hello
$ ecno "foo" > bar
bash: ecno: command not found
$cat bar
  1. If bar would not exist, redirection would created it.
  2. If bar exists and a command did not work, it erases the content of bar.

But it does not copy any output into bar (since there is no output), so it should be said 'redirection is executed PARTIALLY before a command', since the one part of '>' did not work here, namely copying the output of the command into a file bar. Is it right?

Arronical
  • 19,893
Josef Klimuk
  • 1,596
  • 1
    If there was no output to copy, then how can you say copying the output did not work? – muru Aug 02 '18 at 05:25
  • To clarify one thing: ">" only redirects stdout. There is output from your command - bash: ecno: command not found - but this is not redirected to the bar file because error output goes to stderr instead. – user13161 Aug 02 '18 at 14:23
  • @user13161 Correct. > is for stdout stream, or more verbosely 1> redirects stdout. stderr is not redirected, hence it still goes to the screen. It is form of output, just not the implied stdout that user expected. – Sergiy Kolodyazhnyy Aug 02 '18 at 14:52

2 Answers2

9

From bash manual section 3.6.2:

...if it does exist it is truncated to zero size.

Redirection with > file always truncates file before executing command, which means contents are erased regardless of the output; the actual writing to file will take place if there is an actual output (most notably observed with the lack of write() call in strace -f -e open,dup2,write bash -c 'true > out2.txt') and if no further error occurs.

Therefore, everything works properly, as per specifications, and the wording is correct. In fact this behavior is specified by POSIX Shell Command Language specifications and is supported by all POSIX-compliant shells, including ksh and dash (aka Ubuntu's /bin/sh, see the related question).


On the system level, redirection is performed by dup family of system calls, which is why redirection is formally called duplicating file descriptors and is most prominent when we perform the >/dev/null 2&>1 type of redirection.

It can be observed with strace command in the following example of successful and failed command. Note how the files are opened with O_CREAT|O_TRUNC flag.

$ strace -f -e open,dup2,write bash -c 'nocommand > out.txt;echo "foobar" > out2.txt'
...
strace: Process 9633 attached
[pid  9633] open("out.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
[pid  9633] dup2(3, 1)                  = 1
...
...
[pid  9633] write(2, "bash: nocommand: command not fou"..., 35bash: nocommand: command not found
) = 35
[pid  9633] +++ exited with 127 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=9633, si_uid=1000, si_status=127, si_utime=0, si_stime=0} ---
open("out2.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 3
dup2(3, 1)                              = 1
write(1, "foobar\n", 7)                 = 7
dup2(10, 1)                             = 1
+++ exited with 0 +++
Sergiy Kolodyazhnyy
  • 105,154
  • 20
  • 279
  • 497
2

Well, the second part worked, in that it copied the empty output into the file.

For instance, if you redirect stderr with 2> instead of stdout, you'll see that the error makes it into that file:

$ ecno "foo" 2> bar
$

And the contents of "bar" are updated to:

$ cat bar
-bash: ecno: command not found

The fact that the file gets truncated is part of how the redirection works too.

I hope this helps you make sense of how redirection works!

filbranden
  • 2,631
  • Actually, "contents are erased regardless of the output", as @Sergiy Kolodyazhnyy wrote... And this was my understanding also. Three part of redirection: 1. Touching a file to which redirection will be done; 2. erases its content regardless of the output; 3. Copies the redirected output – Josef Klimuk Aug 02 '18 at 05:40
  • 1
    @JosefKlimuk 2 parts of redirection: 1. Open a file, creating and truncating if necessary, 2. send output to the opened file. (1) happens in a single system call. – muru Aug 02 '18 at 05:46
  • Thanks, @muru. So, IMO, in linux learning sources should be written clearly about these two parts of redirection, and when just one of these two parts is executed - it should be articulated explicitly. – Josef Klimuk Aug 02 '18 at 05:53
  • 1
    @JosefKlimuk And to add to muru's comment , I've updated my answer, so you can see the actual syscalls performed – Sergiy Kolodyazhnyy Aug 02 '18 at 05:58
  • 1
    @JosefKlimuk I do agree that this should be explained clearly, but there's also a reason why simplicity is kept there. In the past people dealing with operating systems and system administration were much more likely to be familiar with system-level programming. Nowadays systems are quite complex, so the language is kept way too simple without going into too much details; the concise explanation has its side effects, I guess. – Sergiy Kolodyazhnyy Aug 02 '18 at 06:02