This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the bash category.
Last Updated: 2024-11-21
echo hi > file
- changes file descriptor 1 (STDOUT) to file. Same as 1>file
Therefore, if you do a command that also has errors as well as normal output, it won't appear in the file. Here's proof:
# Running ls a real dir (tmp) and a non-existent one
$ ls /tmp/ doesnotexist > file
# In the terminal, we get an error about the non-existent directory, but nothing
# about /tmp
=> ls doesnotexist: No such file or directory
# But when we look inside the file, it has the normal non-error output (but no mention of the error)
cat file
filea filb
Next up, cat < file
- changes file descriptor 0 to file. I.e. takes input from there
And lastly, pipe wires STDOUT of one command to STDIN of others echo foo | cat
2>
without any ampersand.e.g. ls /tmp doesnotexist 2> errfile
. This puts the STDERR in errfile (and prevents it being printed on the terminal)
# Send errors to one file and normal output to another
$ ls /tmp/ doesnotexist 2> errfile 1> file
# Prove it worked
$ cat errfile
ls: doesnotexist: No such file or directory
$ cat file
realfile.docx anotherrealfile.pdf
The following code combines STDERR into STDOUT. Now the pipe can read from STDERR as well (probably not what you want though!) However watch out - pipes can therefore swallow errors silently...
ls /tmp/ doesnotexist 2>&1 | cat
Meaning of 2>&1
- something written on STDERR will go to whatever 1 references
(i.e. STDOUT)
command 2>&1 > file
is not the same as command >file 2>&1
Why the difference? The key is that the redirection (kinda like C pointers -
reminder: & deferencing) just gives a reference to its current value. So in
the first command, stderr is redirected to whatever fd1 is at the time, which,
is /dev/ttys006
as shown by lsof
when you ask it what is connected to the
current process of the shell ($$
)
$ lsof -p $$
zsh 54371 jack 0u CHR 16,6 0t1686916 5705 /dev/ttys006
zsh 54371 jack 1u CHR 16,6 0t1686916 5705 /dev/ttys006
zsh 54371 jack 2u CHR 16,6 0t1686916 5705 /dev/ttys006
zsh 54371 jack 10u CHR 16,6 0t115249 5705 /dev/ttys006
# CHR – Character special file
Shell commands have many "outputs" - aside from what's sent to fd1 & fd2, there is a return code which can be used in logic, and a process id (say if it was backgrounded).