Asked  7 Months ago    Answers:  5   Viewed   107 times

I want to redirect both stdout and stderr of a process to a single file. How do I do that in Bash?

 Answers

62

Take a look here. Should be:

yourcommand &>filename

(redirects both stdout and stderr to filename).

Tuesday, June 1, 2021
 
seaders
answered 7 Months ago
65
cmd >>file.txt 2>&1

Bash executes the redirects from left to right as follows:

  1. >>file.txt: Open file.txt in append mode and redirect stdout there.
  2. 2>&1: Redirect stderr to "where stdout is currently going". In this case, that is a file opened in append mode. In other words, the &1 reuses the file descriptor which stdout currently uses.
Tuesday, June 1, 2021
 
Skipper
answered 7 Months ago
49

This error:

ls: *.xyz: No such file or directory

is being written on stderr by ls binary.

However in this command:

ls -al *.xyz 2>&1 1> files.lst

You're first redirecting stderr to stdout which by default goes to tty (terminal)

And then you're redirecting stdout to a file files.lst, however remember that stderr doesn't redirected to file since you have stderr to stdout redirection before stdout to file redirection. Your stderr still gets written to tty in this case.

However in 2nd case you change the order of redirections (first stdout to file and then stderr to stdout) and that rightly redirects stderr to a file which is also being used by stdout.

Thursday, June 3, 2021
 
Anand
answered 6 Months ago
49

The csh shell has never been known for its extensive ability to manipulate file handles in the redirection process.

You can redirect both standard output and error to a file with:

xxx >& filename

but that's not quite what you were after, redirecting standard error to the current standard output.


However, if your underlying operating system exposes the standard output of a process in the file system (as Linux does with /dev/stdout), you can use that method as follows:

xxx >& /dev/stdout

This will force both standard output and standard error to go to the same place as the current standard output, effectively what you have with the bash redirection, 2>&1.

Just keep in mind this isn't a csh feature. If you run on an operating system that doesn't expose standard output as a file, you can't use this method.


However, there is another method. You can combine the two streams into one if you send it to a pipeline with |&, then all you need to do is find a pipeline component that writes its standard input to its standard output. In case you're unaware of such a thing, that's exactly what cat does if you don't give it any arguments. Hence, you can achieve your ends in this specific case with:

xxx |& cat

Of course, there's also nothing stopping you from running bash (assuming it's on the system somewhere) within a csh script to give you the added capabilities. Then you can use the rich redirections of that shell for the more complex cases where csh may struggle.

Let's explore this in more detail. First, create an executable echo_err that will write a string to stderr:

#include <stdio.h>
int main (int argc, char *argv[]) {
    fprintf (stderr, "stderr (%s)n", (argc > 1) ? argv[1] : "?");
    return 0;
}

Then a control script test.csh which will show it in action:

#!/usr/bin/csh

ps -ef ; echo ; echo $$ ; echo

echo 'stdout (csh)'
./echo_err csh

bash -c "( echo 'stdout (bash)' ; ./echo_err bash ) 2>&1"

The echo of the PID and ps are simply so you can ensure it's csh running this script. When you run this script with:

./test.csh >test.out 2>test.err

(the initial redirection is set up by bash before csh starts running the script), and examine the out/err files, you see:

test.out:
    UID     PID    PPID  TTY        STIME     COMMAND
    pax    5708    5364  cons0      11:31:14  /usr/bin/ps
    pax    5364    7364  cons0      11:31:13  /usr/bin/tcsh
    pax    7364       1  cons0      10:44:30  /usr/bin/bash

    5364

    stdout (csh)
    stdout (bash)
    stderr (bash)

test.err:
    stderr (csh)

You can see there that the test.csh process is running in the C shell, and that calling bash from within there gives you the full bash power of redirection.

The 2>&1 in the bash command quite easily lets you redirect standard error to the current standard output (as desired) without prior knowledge of where standard output is currently going.

Tuesday, June 22, 2021
 
IvanH
answered 6 Months ago
18

You've attempted to write to the output stream before you attempt to listen on the input stream, so it makes sense that you're seeing nothing. For this to succeed, you will need to use separate threads for your two streams.

i.e.,

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Scanner;

public class Foo {
   public static void main(String[] args) throws IOException {
      Process cmd = Runtime.getRuntime().exec("cmd.exe");

      final InputStream inStream = cmd.getInputStream();
      new Thread(new Runnable() {
         public void run() {
            InputStreamReader reader = new InputStreamReader(inStream);
            Scanner scan = new Scanner(reader);
            while (scan.hasNextLine()) {
               System.out.println(scan.nextLine());
            }
         }
      }).start();

      OutputStream outStream = cmd.getOutputStream();
      PrintWriter pWriter = new PrintWriter(outStream);
      pWriter.println("echo Hello World");
      pWriter.flush();
      pWriter.close();
   }
}

And you really shouldn't ignore the error stream either but instead should gobble it, since ignoring it will sometimes fry your process as it may run out of buffer space.

Friday, June 25, 2021
 
Bharanikumar
answered 6 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share