Redirections from script himself
You could plan redirections from the script itself:
#!/bin/bash
exec 1>>logfile.txt
exec 2>&1
/bin/ls -ld /tmp /tnt
Running this will create/append logfile.txt
, containing:
/bin/ls: cannot access '/tnt': No such file or directory
drwxrwxrwt 2 root root 4096 Apr 5 11:20 /tmp
Or
#!/bin/bash
exec 1>>logfile.txt
exec 2>>errfile.txt
/bin/ls -ld /tmp /tnt
While create or append standard output to logfile.txt
and create or append errors output to errfile.txt
.
Log to many different files
You could create two different logfiles, appending to one overall log and recreating another last log:
#!/bin/bash
if [ -e lastlog.txt ] ;then
mv -f lastlog.txt lastlog.old
fi
exec 1> >(tee -a overall.log /dev/tty >lastlog.txt)
exec 2>&1
ls -ld /tnt /tmp
Running this script will
- if
lastlog.txt
already exist, rename them tolastlog.old
(overwritinglastlog.old
if they exist). - create a new
lastlog.txt
. - append everything to
overall.log
- output everything to the terminal.
Simple and combined logs
#!/bin/bash
[ -e lastlog.txt ] && mv -f lastlog.txt lastlog.old
[ -e lasterr.txt ] && mv -f lasterr.txt lasterr.old
exec 1> >(tee -a overall.log combined.log /dev/tty >lastlog.txt)
exec 2> >(tee -a overall.err combined.log /dev/tty >lasterr.txt)
ls -ld /tnt /tmp
So you have
lastlog.txt
last run log filelasterr.txt
last run error filelastlog.old
previous run log filelasterr.old
previous run error fileoverall.log
appended overall log fileoverall.err
appended overall error filecombined.log
appended overall error and log combined file.- still output to the terminal
And for interactive session, use stdbuf
:
stdbuf
: Regarding Fonic’ comment and after some test, I have to agree: with tee
, stdbuf
is useless. But …
If you plan to use this in *interactive* shell, you must tell `tee` to not buffering his input/output:
# Source this to multi-log your session
[ -e lasterr.txt ] && mv -f lasterr.txt lasterr.old
[ -e lastlog.txt ] && mv -f lastlog.txt lastlog.old
exec 2> >(exec stdbuf -i0 -o0 tee -a overall.err combined.log /dev/tty >lasterr.txt)
exec 1> >(exec stdbuf -i0 -o0 tee -a overall.log combined.log /dev/tty >lastlog.txt)
Once sourced this, you could try:
ls -ld /tnt /tmp
More complex sample
From my 3 remarks about how to Convert Unix timestamp to a date string
I’ve used more complex command to parse and reassemble squid
‘s log in real time: As each line begin by an UNIX EPOCH with milliseconds, I split the line on 1st dot, add @
symbol before EPOCH SECONDS to
pass them to date -f - +%F %T
then reassemble date
‘s output and the rest of line with a dot by using paste -d .
.
exec {datesfd}<> <(:)
tail -f /var/log/squid/access.log |
tee >(
exec sed -u 's/^([0-9]+)..*/@1/'|
stdbuf -o0 date -f - +%F %T >&$datesfd
) |
sed -u 's/^[0-9]+.//' |
paste -d . /dev/fd/$datesfd -
With date
, stdbuf
was required…
Some explanations about exec
and stdbuf
commands:
-
Running
forks
by using$(...)
or<(...)
is done by running subshell wich will execute binaries in another subshell (subsubshell). Theexec
command tell shell that there are not further command in script to be run, so binary (stdbuf ... tee
) will be executed as replacement process, at same level (no need to reserve more memory for running another sub-process).From
bash
‘s man page (man -P'less +/^ *exec ' bash
):exec [-cl] [-a name] [command [arguments]] If command is specified, it replaces the shell. No new process is created....
This is not really needed, but reduce system footprint.
-
From
stdbuf
‘s man page:NAME stdbuf - Run COMMAND, with modified buffering operations for its standard streams.
This will tell system to use unbuffered I/O for
tee
command. So all outputs will be updated immediately, when some input are coming.
Fix me: To be continued
Redirection makes it possible to control where the output of a command goes to, and where the input of a command comes from. It’s a mighty tool that, together with pipelines, makes the shell powerful. The redirection operators are checked whenever a simple command is about to be executed.
Under normal circumstances, there are 3 files open, accessible by the file descriptors 0, 1 and 2, all connected to your terminal:
Name | FD | Description |
---|---|---|
stdin |
0 | standard input stream (e.g. keyboard) |
stdout |
1 | standard output stream (e.g. monitor) |
stderr |
2 | standard error output stream (usually also on monitor) |
The terms «monitor» and «keyboard» refer to the same device, the terminal here. Check your preferred UNIX®-FAQ for details, I’m too lazy to explain what a terminal is
Both, stdout
and stderr
are output file descriptors. Their difference is the convention that a program outputs payload on stdout
and diagnostic- and error-messages on stderr
. If you write a script that outputs error messages, please make sure you follow this convention!
Whenever you name such a filedescriptor, i.e. you want to redirect this descriptor, you just use the number:
# this executes the cat-command and redirects its error messages (stderr) to the bit bucket cat some_file.txt 2>/dev/null
Whenever you reference a descriptor, to point to its current target file, then you use a «&
» followed by a the descriptor number:
# this executes the echo-command and redirects its normal output (stdout) to the standard error target echo "There was an error" 1>&2
The redirection operation can be anywhere in a simple command, so these examples are equivalent:
cat foo.txt bar.txt >new.txt cat >new.txt foo.txt bar.txt >new.txt cat foo.txt bar.txt
Every redirection operator takes one or two words as operands. If you have to use operands (e.g. filenames to redirect to) that contain spaces you must quote them!
Valid redirection targets and sources
This syntax is recognized whenever a TARGET
or a SOURCE
specification (like below in the details descriptions) is used.
Syntax | Description |
---|---|
FILENAME |
references a normal, ordinary filename from the filesystem (which can of course be a FIFO, too. Simply everything you can reference in the filesystem) |
&N |
references the current target/source of the filedescriptor N («duplicates» the filedescriptor) |
&- |
closes the redirected filedescriptor, useful instead of > /dev/null constructs (> &- ) |
/dev/fd/N |
duplicates the filedescriptor N , if N is a valid integer |
/dev/stdin |
duplicates filedescriptor 0 (stdin ) |
/dev/stdout |
duplicates filedescriptor 1 (stdout ) |
/dev/stderr |
duplicates filedescriptor 2 (stderr ) |
/dev/tcp/HOST/PORT |
assuming HOST is a valid hostname or IP address, and PORT is a valid port number or service name: redirect from/to the corresponding TCP socket |
/dev/udp/HOST/PORT |
assuming HOST is a valid hostname or IP address, and PORT is a valid port number or service name: redirect from/to the corresponding UDP socket |
If a target/source specification fails to open, the whole redirection operation fails. Avoid referencing file descriptors above 9, since you may collide with file descriptors Bash uses internally.
N > TARGET
This redirects the file descriptor number N
to the target TARGET
. If N
is omitted, stdout
is assumed (FD 1). The TARGET
is truncated before writing starts.
If the option noclobber
is set with the set builtin, with cause the redirection to fail, when TARGET
names a regular file that already exists. You can manually override that behaviour by forcing overwrite with the redirection operator >|
instead of >
.
N >> TARGET
This redirects the file descriptor number N
to the target TARGET
. If N
is omitted, stdout
is assumed (FD 1). The TARGET
is not truncated before writing starts.
Redirecting output and error output
&> TARGET
>& TARGET
This special syntax redirects both, stdout
and stderr
to the specified target. It’s equivalent to
> TARGET 2>&1
Since Bash4, there’s &>>TARGET
, which is equivalent to >> TARGET 2>&1
.
This syntax is deprecated and should not be used. See the page about obsolete and deprecated syntax.
Appending redirected output and error output
To append the cumulative redirection of stdout
and stderr
to a file you simply do
>> FILE 2>&1
&>> FILE
Transporting stdout and stderr through a pipe
COMMAND1 2>&1 | COMMAND2
COMMAND1 |& COMMAND2
N < SOURCE
The input descriptor N
uses SOURCE
as its data source. If N
is omitted, filedescriptor 0 (stdin
) is assumed.
<<TAG ... TAG
<<-TAG ... TAG
A here-document is an input redirection using source data specified directly at the command line (or in the script), no «external» source. The redirection-operator <<
is used together with a tag TAG
that’s used to mark the end of input later:
# display help cat <<EOF Sorry... No help available yet for $PROGRAM. Hehe... EOF
As you see, substitutions are possible. To be precise, the following substitutions and expansions are performed in the here-document data:
You can avoid that by quoting the tag:
cat <<"EOF" This won't be expanded: $PATH EOF
Last but not least, if the redirection operator <<
is followed by a -
(dash), all leading TAB from the document data will be ignored. This might be useful to have optical nice code also when using here-documents.
The tag you use must be the only word in the line, to be recognized as end-of-here-document marker.
It seems that here-documents (tested on versions 1.14.7
, 2.05b
and 3.1.17
) are correctly terminated when there is an EOF before the end-of-here-document tag. The reason is unknown, but it seems to be done on purpose. Bash 4 introduced a warning message when end-of-file is seen before the tag is reached.
<<< WORD
The here-strings are a variation of the here-documents. The word WORD
is taken for the input redirection:
cat <<< "Hello world... $NAME is here..."
Just beware to quote the WORD
if it contains spaces. Otherwise the rest will be given as normal parameters.
The here-string will append a newline (n
) to the data.
More redirection operations can occur in a line of course. The order is important! They’re evaluated from left to right.
If you want to redirect both, stderr
and stdout
to the same file (like /dev/null
, to hide it), this is the wrong way:
# { echo OUTPUT; echo ERRORS >&2; } is to simulate something that outputs to STDOUT and STDERR # you can test with it { echo OUTPUT; echo ERRORS >&2; } 2>&1 1>/dev/null
Why? Relatively easy:
What remains? stdout
goes to /dev/null
, stderr
still (or better: «again») goes to the terminal. You have to swap the order to make it do what you want:
{ echo OUTPUT; echo ERRORS >&2; } 1>/dev/null 2>&1
How to make a program quiet (assuming all output goes to STDOUT
and STDERR
?
command >/dev/null 2>&1
# Append vs Truncate
# Truncate >
- Create specified file if it does not exist.
- Truncate (remove file’s content)
- Write to file
# Append >>
- Create specified file if it does not exist.
- Append file (writing at end of file).
# Redirecting both STDOUT and STDERR
File descriptors like 0
and 1
are pointers. We change what file descriptors point to with redirection. >/dev/null
means 1
points to /dev/null
.
First we point 1
(STDOUT
) to /dev/null
then point 2
(STDERR
) to whatever 1
points to.
This can be further shortened to the following:
However, this form may be undesirable in production if shell compatibility is a concern as it conflicts with POSIX, introduces parsing ambiguity, and shells without this feature will misinterpret it:
NOTE: &>
is known to work as desired in both Bash and Zsh.
# Redirecting standard output
>
redirect the standard output (aka STDOUT
) of the current command into a file or another descriptor.
These examples write the output of the ls
command into the file file.txt
The target file is created if it doesn’t exists, otherwise this file is truncated.
The default redirection descriptor is the standard output or 1
when none is specified.
This command is equivalent to the previous examples with the standard output explicitly indicated:
Note: the redirection is initialized by the executed shell and not by the executed command, therefore it is done before the command execution.
# Using named pipes
Sometimes you may want to output something by one program and input it into another program, but can’t use a standard pipe.
You could simply write to a temporary file:
This works fine for most applications, however, nobody will know what tempFile
does and someone might remove it if it contains the output of ls -l
in that directory. This is where a named pipe comes into play:
myPipe
is technically a file (everything is in Linux), so let’s do ls -l
in an empty directory that we just created a pipe in:
The output is:
Notice the first character in the permissions, it’s listed as a pipe, not a file.
Now let’s do something cool.
Open one terminal, and make note of the directory (or create one so that cleanup is easy), and make a pipe.
Now let’s put something in the pipe.
You’ll notice this hangs, the other side of the pipe is still closed. Let’s open up the other side of the pipe and let that stuff through.
Open another terminal and go to the directory that the pipe is in (or if you know it, prepend it to the pipe):
You’ll notice that after hello from the other side
is output, the program in the first terminal finishes, as does that in the second terminal.
Now run the commands in reverse. Start with cat < myPipe
and then echo something into it. It still works, because a program will wait until something is put into the pipe before terminating, because it knows it has to get something.
Named pipes can be useful for moving information between terminals or between programs.
Pipes are small. Once full, the writer blocks until some reader reads the contents, so you need to either run the reader and writer in different terminals or run one or the other in the background:
More examples using named pipes:
Mind that first contents of file3
are displayed and then the ls -l
data is displayed (LIFO configuration).
Mind that the variable $pipedata
is not available for usage in the main terminal / main shell since the use of &
invokes a subshell and $pipedata
was only available in this subshell.
This prints correctly the value of $pipedata
variable in the main shell due to the export declaration of the variable. The main terminal/main shell is not hanging due to the invocation of a background shell (&
).
# Redirecting multiple commands to the same file
# Print error messages to stderr
Error messages are generally included in a script for debugging purposes or for providing rich user experience. Simply writing error message like this:
may work for simple cases but it’s not the usual way. In this example, the error message will pollute the actual output of the script by mixing both errors and successful output in stdout
.
In short, error message should go to stderr
not stdout
. It’s pretty simple:
Another example:
In the above example, the success message will be printed on stdout
while the error message will be printed on stderr
.
A better way to print error message is to define a function:
Now, when you have to print an error:
# Redirection to network addresses
Bash treats some paths as special and can do some network communication by writing to /dev/{udp|tcp}/host/port
. Bash cannot setup a listening server, but can initiate a connection, and for TCP can read the results at least.
For example, to send a simple web request one could do:
and the results of www.google.com
‘s default web page will be printed to stdout
.
Similarly
would send a UDP message containing HIn
to a listener on 192.168.1.1:6666
# Redirecting STDIN
<
reads from its right argument and writes to its left argument.
To write a file into STDIN
we should read /tmp/a_file
and write into STDIN
i.e 0</tmp/a_file
Note: Internal file descriptor defaults to 0
(STDIN
) for <
# Redirecting STDERR
2
is STDERR
.
Definitions:
echo_to_stderr
is a command that writes "stderr"
to STDERR
# STDIN, STDOUT and STDERR explained
Commands have one input (STDIN) and two kinds of outputs, standard output (STDOUT) and standard error (STDERR).
For example:
STDIN
Standard input is used to provide input to a program.
(Here we’re using the read
builtin (opens new window) to read a line from STDIN.)
STDOUT
Standard output is generally used for «normal» output from a command. For example, ls
lists files, so the files are sent to STDOUT.
STDERR
Standard error is (as the name implies) used for error messages. Because this message is not a list of files, it is sent to STDERR.
STDIN, STDOUT and STDERR are the three standard streams. They are identified to the shell by a number rather than a name:
0 = Standard in
1 = Standard out
2 = Standard error
By default, STDIN is attached to the keyboard, and both STDOUT and STDERR appear in the terminal. However, we can redirect either STDOUT or STDERR to whatever we need. For example, let’s say that you only need the standard out and all error messages printed on standard error should be suppressed. That’s when we use the descriptors 1
and 2
.
Redirecting STDERR to /dev/null
Taking the previous example,
In this case, if there is any STDERR, it will be redirected to /dev/null (a special file which ignores anything put into it), so you won’t get any error output on the shell.
# Syntax
- command </path/to/file # Redirect standard input to file
- command >/path/to/file # Redirect standard output to flie
- command file_descriptor>/path/to/file # Redirect output of file_descriptor to file
- command >&file_descriptor # Redirect output to file_descriptor
- command file_descriptor>&another_file_descriptor # Redirect file_descriptor to another_file_descriptor
- command <&file_descriptor # Redirect file_descriptor to standard input
- command &>/path/to/file # Redirect standard output and standard error to file
# Parameters
Parameter | Details |
---|---|
internal file descriptor | An integer. |
direction | One of > , < or <> |
external file descriptor or path | & followed by an integer for file descriptor or a path. |
UNIX console programs have an input file and two output files (input and output streams, as well as devices, are treated as files by the OS.) These are typically the keyboard and screen, respectively, but any or all of them can be redirected to come from — or go to — a file or other program.
STDIN
is standard input, and is how the program receives interactive input. STDIN
is usually assigned file descriptor 0.
STDOUT
is standard output. Whatever is emitted on STDOUT
is considered the «result» of the program. STDOUT
is usually assigned file descriptor 1.
STDERR
is where error messages are displayed. Typically, when running a program from the console, STDERR
is output on the screen and is indistinguishable from STDOUT
. STDERR
is usually assigned file descriptor 2.
The order of redirection is important
Redirects both (STDOUT
and STDERR
) to the file.
Redirects only STDOUT
, because the file descriptor 2 is redirected to the file pointed to by file descriptor 1 (which is not the file file
yet when the statement is evaluated).
Each command in a pipeline has its own STDERR
(and STDOUT
) because each is a new process. This can create surprising results if you expect a redirect to affect the entire pipeline. For example this command (wrapped for legibility):
will print «Python error!» to the console rather than the log file. Instead, attach the error to the command you want to capture:
In this tutorial we are going to learn How to use Output redirection and Pipes in Linux Bash environment.
In Linux bash there is Two types of Outputs, stdout (Standard Output) and stderr (Standard Error).
- Standard Output also known as stdout is the output of a Linux command or program. For example stdout of the ls command is the List Files and Directories.
- Standard Errors — Commands also give errors. For example, if you run the ls command on a file that do not exist, it will give an error message ‘No such file or directory’.
Also note that one command can output both stdout and stderr at the same time. For example, You are trying to concatenate two files ‘txt1’and ‘txt2’ with cat command, but the file ‘txt2’ does not exist on the system.
cat txt1 txt2
This is TXT 1
cat: txt2: No such file or directory
As per the preceding example, cat command first reads the ‘txt1’ and output its content «This is TXT 1». Then it will try to read txt2 and send the error «No such file or directory» since txt2 not exist.
By default both Stdout and Stderr sends to the Linux terminal.
Bash Output Redirection Operators
Following table shows operators used in Linux output redirection.
Operator | Redirection Type |
> | Redirect stdout to a file. |
>> | Redirect stdout to a file, append to current file instead of overwriting. |
2> | Redirect stderr to a file. |
2>> | Redirect stderr to a file, append to current file instead of overwriting. |
&> | Send both stdout and stderr to one file. |
2>&1 | Redirect stderr to the same location as stdout. |
| | Send output of a one command to another command as input. |
|& | Send both output and errors of a one command to another command as input. |
Redirect Standard Output to a File
Using bash output redirection we can send both stdout and stderr to a file. Redirection of stdout is controlled by «>» the greater-than symbol.
For example, following command will redirect the output of the ls command to file called list.txt:
ls -l > list.txt
Echo «Hello World» to a Text File:
echo "Hello World" > hello.txt
As you can see, to redirect the output we use the greater than operator (>). If the file does not exist, it will be created, and if it exists, its content is overwritten with the output of the Command.
The double greater-than sign (>>) append the output to the file instead of overwriting.
ls -l >> list.txt
Note that we are only redirecting Standard Output, any error message still goes to the Linux terminal window.
Send Standard Error to a File
Standard Errors represented by No ‘2’, so we use 2> operator to redirect stderr.
cat file1 nofile 2> error.txt
As per the preceding example, any error message will redirect to the error.txt file.
The ‘2>>’ operator will append stderr to the file.
cat file1 nofile 2>> error.txt
Redirect Both Standard Output and Standard Errors
We can redirect output and errors into two different file or to the same file.
Following example will redirect stdout to the stdout.txt file, Errors will send to the stderr.txt file.
cat file1 nofile > stdout.txt 2> stderr.txt
To redirect both outputs to the same file we use ‘&>’ operator.
cat file1 nofile &> output.txt
Following Format also can be used (The order matters):
cat file1 nofile > output.txt 2>&1
This tells cat command to send stdout to output.txt followed by ‘2>&1’ operator tells that errors also should be redirect to the same location as stdout (output.txt).
Send stdout and stderr to /dev/null
The /dev/null is a special file in Linux, Anything sent to the /dev/null is going to disappear. Anything we don’t want to see, we send it to the /dev/null.
This is mostly used in Linux shell scripting where we don’t want any output.
Examples
Run find command to search for passwd file in /etc directory and send Standard errors to /dev/null:
find /etc -name passwd 2> /dev/null
Search for the passwd file, output sends to the output.txt and standard errors to /dev/null:
find /etc -name passwd > output.txt 2> /dev/null
Send both stdout and stderr to /dev/null:
systemctl restart httpd > /dev/null 2>&1
Redirection with Pipe and pipelines
Another powerful bash feature is that the output from one command can be used as the input to another command, This is done by using Pipe (|) symbol. This is often used with the Linux grep command to filter the output.
In the following example, we pipe the output of the ls to grep command:
ls -l /usr/bin/ | grep python
If the directory list is too long to fit on the screen, we can pipe its output to the less command:
ls -l /usr/bin/ | grep python | less
Even though it looks simple, Output Redirection is quite useful feature in bash, especially when you write shell scripts.