Search code examples
bashzshio-redirection

How to redirect stdout of zsh/bash and restore later


In python, you can

sys.stdout = open('log', 'w') # begin redirect

then output will write to log instead.

You can restore back to normal behavior with

sys.stdout = sys.__stdout__   # end redirect, restore back

How to achieve similar effect in zsh & bash?

P.S.,

  • stdout of command in subshell should also be redirected.
  • ls > log is not what I want.

To clarify, what I want is

ls   # output to terminal
# begin redirect to `log`
ls   # output to `log`
find -type f   # output to `log`
...  # output to `log`
# end redirect, restore back
ls   # output to terminal

Edit Below are not what I want

  • redirection a group of command.
  • tail -f for monitoring.

As The first few lines of this question stated, what I want is

# ...
cmd1    # normal behavior
# begin redirection
cmd2   # redirect to file
# some times later
cmd2   # redirect to file
# ...
cmdN   # redirect to file
# end redirection
cmdN+1 # normal behavior
# ...

Solution

  • Typically, you would redirect output for a command group, rather than redirecting and restoring output for the shell itself.

    ls                    # to terminal
    {
      ls
      find -type f
    } > log               # to log
    ls                    # to terminal again
    

    Standard output for the command group delimited by { ... } as a whole is redirected to a file. The commands in that group inherit their standard output from the group, not directly from the shell.

    This is similar to doing the following in Python:

    from contextlib import redirect_stdout
    
    print("listing files to terminal")
    with open("log", "w") as f, redirect_stdout(f):
        print("listing files to log")
        print("finding files")
    print("listing files to terminal")
    

    In shell, the equivalent of your forced redirection of standard output can be accomplished by using exec, as demonstrated by oguz ismail, though the command group makes it clearer where the redirection begins and ends. (It also avoids needing to find an unused file descriptor and remembering even more arcane shell syntax.)