Redirect error output bash

To redirect standard output to a truncated file in Bash, I know to use: cmd > file.txt To redirect standard output in Bash, appending to a file, I know to use: cmd >> file.txt To redirec...

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 to lastlog.old (overwriting lastlog.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 file
  • lasterr.txt last run error file
  • lastlog.old previous run log file
  • lasterr.old previous run error file
  • overall.log appended overall log file
  • overall.err appended overall error file
  • combined.log appended overall error and log combined file.
  • still output to the terminal

And for interactive session, use 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). The exec 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 >

  1. Create specified file if it does not exist.
  2. Truncate (remove file’s content)
  3. Write to file

# Append >>

  1. Create specified file if it does not exist.
  2. 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:

  • Example 1 — all commands on the same terminal / same shell
  • Example 2 — all commands on the same terminal / same shell

    Mind that first contents of file3 are displayed and then the ls -l data is displayed (LIFO configuration).

  • Example 3 — all commands on the same terminal / same shell

    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.

  • Example 4 — all commands on the same terminal / same shell

    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.

    Понравилась статья? Поделить с друзьями:
  • Redefinition of error xcode
  • Redefinition of class c как исправить
  • Reddragon mitra как изменить подсветку
  • Red4ext cyberpunk 2077 ошибка при запуске
  • Red state asus как исправить