Learn Docker With My Newest Course

Dive into Docker takes you from "What is Docker?" to confidently applying Docker to your own projects. It's packed with best practices and examples. Start Learning Docker →

Redirect Multiple Commands or an Entire Script to a File

redirect-multiple-commands-or-an-entire-script-to-a-file.jpg

We'll go over a few examples such as running a few commands of your choosing as well as redirecing all commands in a script.

Quick Jump:

We all know the drill, you can run:

  • echo "hello" > /tmp/cool to redirect the text “hello” to a file, overwriting it
  • echo "hello" >> /tmp/cool to redirect the text “hello” to a file, appending to it

But what if you want to redirect a bunch of commands’ stdout / stderr to a file?

# The Bad Way

Technically you can do this:

whoami >>/tmp/cool
ls -la >>/tmp/cool
echo "Nice" >>/tmp/cool

It’s funny how your brain works. That’s what I started to do when I had a use case to redirect about 10 commands to a file. By the time I got to command 2 I thought to myself “there’s no way this is a good way to do this”. I call this the spidey-sense for detecting horse shit solutions.

ShellCheck also very quickly let me know of alternative ways!

There has to be a better way.

# Command Groups

Let’s say you have a long script but you only want to redirect a handful of commands to a file. For that we can use command groups { ... }:

{
  whoami
  ls -la
  echo "Nice"
} >/tmp/cool 2>&1

echo "Extra commands here not redirected"

The above is POSIX compliant too, as long as you either use new lines to break up your commands or use ; (including the last item) for 1 line groups.

The 2>&1 bit at the end just makes sure all stdout and stderr gets redirected, it’s not specific to command groups.

I included the last echo command because this won’t be redirected. It will echo normally. That’s expected because it’s not within {}.

The benefit of the above approach is it lets you control which commands you want to redirect to a file. You can even have multiple sets of {} redirecting their output to different files. It’s up to you!

Command groups are not limited to this. I’ve written about them in the past when setting up conditional pipes when it came to situationally doing something based on a flag being set for an unrelated script.

# exec

Everything below that exec line will be redirected to that file:

echo "Extra commands here not redirected"

exec > /tmp/cool 2>&1

whoami
ls -la
echo "Nice"

When you combine exec with redirecting, it modifies the file descriptors of the current shell instead of running things in a new subprocess.

It’s not straight forward to revert this mid-script so I typically associate using this strategy as redirecting an entire script’s output to a file. Technically you can save and restore stdout / stderr to different file descriptors but that goes beyond the scope of this post.

The benefit of using this instead of command groups is if you have a lot of commands being redirected to a file you can avoid wrapping them all in {}. It could make the script easier to read if you indent everything in {}. It also makes refactoring easier if you decide to temporarily adjust things to output normally by commenting out that single exec line.

With that said, instead of handling this in the script you can choose to run the script normally but redirect it to a file at call time with ./myscript > /tmp/cool. Still, there may be a time and place for doing it within the script and now you have this option!

The video below demos all of the above examples.

# Demo Video

Timestamps

  • 0:34 – The bad way
  • 1:27 – Using command groups
  • 2:50 – Using exec

Have you ever had to do this in one of your scripts? Let me know below.

Never Miss a Tip, Trick or Tutorial

Like you, I'm super protective of my inbox, so don't worry about getting spammed. You can expect a few emails per year (at most), and you can 1-click unsubscribe at any time. See what else you'll get too.



Comments