• Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar
NameHero® Blog

NameHero® Blog

Web Hosting Tips & Resources From NameHero

  • AI Agents
    • OpenClaw
    • Claude Code
    • n8n
    • Hermes Agent
    • Open WebUI
    • Docker
  • Hosting
    • Web Hosting
    • WordPress Hosting
    • WooCommerce Hosting
    • Enterprise Hosting
    • Email Hosting
    • HeroicGuard
    • GPU Hosting
    • Website Builder
  • VPS
    • Managed VPS
    • Unmanaged VPS
    • Flex VPS
  • Reseller
  • Gaming
  • Domains
  • Account
  • Blog Home
  • Categories
  • Authors

Bash File Descriptors Explained

Bhagwad Park

Published on: January 21, 2026

Categories: VPS Hosting 0

In Linux, a fundamental principle is that “everything is a file.” When a process starts, all the resources available to it are designated as a file. We’ve already learned about how files in Linux are represented by inodes in the article on symbolic links vs hard links, but this article talks about the internal representation of resources as files, not actual files that sit on the disk. These resources are designated by “file descriptors”, and we can use these descriptors to change how these resources interact with the system.

The most commonly known file descriptors in Linux are the following three:

  1. stdin
  2. stdout
  3. stderr

These three streams are available to all processes by default. In the past, we’ve talked about how to redirect stderr to stdout, but no mention was made of file descriptors. In reality, the numbers 0, 1, and 2 that we use when referring to the above streams are the file descriptors for those streams. In this, we’ll look at how we can use these file descriptors in redirection and some other advanced use-cases.

Table of Contents
  • Redirecting Streams – the Most Common Use Case
    • Redirecting Semi-Permanently
  • How to Use File Descriptors in Common Commands
    • Accessing File Descriptors Through File Paths
  • Using FDs in Scripts
  • Conclusion

Redirecting Streams – the Most Common Use Case

Since we’ve already covered the redirection of streams elsewhere, there’s no need to go into detail. Suffice to say that we can redirect the output of a command to a file like this:

ls > files.txt

The above command is a shorthand for “Redirect FD 1 to files.txt”. Similarly, we can redirect FD 0 by using the “<” symbol like this:

sort < list.txt

This command will tell bash to provide the contents of “list.txt” as input to the “sort” command, instead of seeking input from the keyboard.

Redirecting Semi-Permanently

When we use a command like:

ls -l > output.log

The redirection only works for a single command. If you want to redirect the output for a command after that, you have to type “< > output.log ” again. However, if you want to redirect an output once and apply it to all the subsequent commands in that bash session, you use something like this:

exec > output.log

In this command, we’re telling bash that going forward, we always want the stdout to go to “output.log” instead of the terminal. We can now type commands without the “> output.log” part after it, and bash will use the file automatically as the destination for stdout going forward, regardless of the command.

Let’s see how this works.

Output going to File

In this example, I first use the “exec > output.log”. Because of that, all further output is sent to “output.log” and nothing comes to the terminal. Now, before I can view the contents of “output.log”, I need to send back the output to the terminal. I can’t see the contents of the file! To do that, I type:

exec > /dev/tty

And then I can view the contents of output.log as usual.

While this is a good illustration of how to use exec, it’s not a very useful one, because without the ability to see the output on the screen, you can’t even see the output of any file or command. There are better ways to use “exec” in this way from within scripts that we’ll discuss, but this was only to show you what’s possible.

How to Use File Descriptors in Common Commands

In addition to the above three file descriptors that come by default, we can also create our own FDs. For example, the following command creates a new file descriptor that gets its data from a file. Let’s say I have a file called “input_file.txt” with the following contents:

Contents of Input_File.txt
Contents of Input_File.txt

Now let’s create a new file descriptor that gets its input from this file:

exec 3< input_file.txt

The above command creates a new file descriptor called “3”, and we’re telling the kernel to associate this FD with the data stream from “input_file.txt”. It’s important to note that this file descriptor is not an alias. We can’t just use something like “vi 3” and expect to read the contents of input_file.txt. Other commands are unaware of what we’ve done. Only the kernel knows. To access the data stream via this FD, we need to use something like this:

cat <&3

And now we get the following output:

Accessing the Contents of the File Descriptor

As you can see, we get the same output as before.

Accessing File Descriptors Through File Paths

Linux systems these days also provide a way to access existing file descriptors through the “/dev/fd/” directory. To see the existing file descriptors, we can use a regular “ls -l” command to see the list of existing FDs, and their links, like this:

ls -l /dev/fd/

And here’s the output:

Existing File Descriptors

Here, we can see that the FD we just created has its own entry in the form of a symbolic link to the file destination. This means we can use this particular path in regular commands like this:

cat /dev/fd/3
Accessing the FD via a Path

So we can see the contents of the file in this way. However, it’s best if you don’t use the FD in this way in commands like “vi”, because internally, the FD is a stream of text, and commands like vi can sometimes behave unexpectedly.

Using FDs in Scripts

The most common use of FDs is in scripts, where you want to consistently redirect stdout and stderr to files, instead of the screen. Let’s say you have a script that generates a lot of output via multiple commands. When the user runs the script, you don’t want to inundate them with a lot of screen text. Instead, you want to send everything to a file.

Normally, this wouldn’t be a problem. We can just use something like:

ls > files.txt

And the output would go to “files.txt”, instead of the screen. But if your script has a lot of commands, then you would have to append “>> files.txt” to each one of them, making it harder to read, and you also need to keep remembering to add this even later when you change the script.

Instead, we can use the exec command to redirect all the output to a file, and then, when the commands are done, we can switch it back. Here’s an example:

Step 1: Back up the existing target of stdout. This way, we can revert to these destinations when our commands have finished:

exec 3>&1

So far, nothing has changed.

Step 2: Send all output to a log file from here on out:

exec > backup_log.txt

Step 3: Execute our output-heavy commands:

echo "Starting Backup"
tar etc…
gzip etc…
echo "Backup Complete"

Step 4: Now we switch the target of stdout back to wherever it was before we executed our commands:

exec 1>&3
echo "The backup is finished. Check backup_log.txt for details."

And all is back to normal. The user can access “backup_log.txt” to see the output if they’re interested. Note that we didn’t redirect stderr, so the user will still see if something went wrong on the screen. The “backup_log.txt” file is only for reference.

Conclusion

FDs can be a bit hard to wrap your head around. But once you get the hang of them, it’s easy to see why they can be useful in scripts. You need to be careful not to accidentally redirect stdin to a file using an “exec” command, causing your sessions to crash, though!

Bhagwad Park Profile Picture
Bhagwad Park

I’m a NameHero team member, and an expert on WordPress and web hosting. I’ve been in this industry since 2008. I’ve also developed apps on Android and have written extensive tutorials on managing Linux servers. You can contact me on my website WP-Tweaks.com!

Related Posts

Docker Build Cache – How it Works and Invalidating it

Docker heavily optimizes its build process with caching to save time. But it's important to know how to invalidate it.

When to Use Here-String vs Heredoc in Bash

Heredoc and Here-string are both ways to input strings into commands that read from stdin. Here's the difference between them.

Bash Debug Mode: set -x and the PS4 Variable

When coding a program, you usually have a full IDE set up with autocomplete and stack tracing, allowing you to pause execution at any point and see what’s going on under the hood. These tools make coding more productive, and they’ve been in use for a long time. But what if you’re just quickly coding […]

How to Tar and Gzip a Folder

Here's how to archive and compress a folder so that it's easy to move it from one location to another - In both Linux AND Windows!

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

Follow & Subscribe

Exclusive promos, content and more!


Most Popular Posts

NameHero’s Recommended WordPress Plugin and Theme Setup

WordPress Hosting vs. Web Hosting – What’s The Difference?

How To Increase The InnoDB Buffer Pool Size

How To Fix A Stuck All-in-One WP Migration Import

How To Add A Subdomain In Cloudflare

Top Categories

  • WordPress
  • WordPress Tutorials
  • OpenClaw Hosting
  • Enterprise Hosting
  • WooCommerce
  • Web Hosting
  • Resellers
  • Website Security
  • Website Development
  • Website Performance
  • VPS Hosting
  • SEO Tips
  • Announcements
  • Domain Registration
NameHero

NameHero® proudly provides web hosting to over 40,000 customers with 99.9% uptime to over 750,000 websites.

  • Master Card
  • Visa
  • American Express
  • Discover
  • Paypal
Products
  • Web Hosting
  • Managed VPS Hosting
  • Unmanaged VPS Hosting
  • Flex VPS Hosting
  • WordPress Hosting
  • WooCommerce Hosting
  • Reseller Hosting
  • Enterprise Hosting
  • GPU Hosting
  • Email Hosting
  • HeroicGuard
  • Domains
  • Website Builder
  • AI Agent Hosting
Help & Support
  • NameHero Blog
  • NameHero Gaming Blog
  • Support
  • Help Center
  • Migrations
  • Affiliates
  • Gaming Affiliates
  • Call 1-855-984-6263
Company
  • About Us
  • Contact Sales
  • Reviews
  • Uptime
  • We're Hiring

Copyright © 2026 Name Hero, LLC. All rights reserved.
NameHero® is a registered trademark.

  • Privacy Policy
  • Terms of Use
  • Acceptable Use Policy
  • Payment Policy
  • DMCA