Back to home

Unix Redirection In C

Published: Jul 28, 2020

Last updated: Jul 28, 2020

This short post is a recount of an exploration into redirection in the C language.

As always, let's go to our friend Wikipedia to set the definition for us:

In computing, redirection is a form of interprocess communication, and is a function common to most command-line interpreters, including the various Unix shells that can redirect standard streams to user-specified locations.

In Unix-like operating systems, programs do redirection with the dup2(2) system call, or its less-flexible but higher-level stdio analogues, freopen(3) and popen(3).

Basic redirection can use < to redirect input and > to redirect output.

For example, we can use the redirect output operator to redirect the output from echo "Hello!" into a file example.txt.

> echo "Hello!" > example.txt > cat example.txt Hello!

As mentioned by our pal Wikipedia, we can use the dup2 system call in C to manage a similar thing!

A simple example

In our first example, we are going to write a simple example of two variables that open a foobar.txt that iterates character by character.

touch foobar.txt one.c

Inside of foobar.txt, add th following:

foobar test

As for the contents of one.c:

#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> int main() { int fd1, fd2; char c; fd1 = open("foobar.txt", O_RDONLY); fd2 = open("foobar.txt", O_RDONLY); // c becomes f read(fd2, &c, 1); // c becomes o read(fd2, &c, 1); // c becomes o read(fd2, &c, 1); // c becomes b read(fd2, &c, 1); printf("c = %c\n", c); // c = b // now reading in fd1, so c becomes f again read(fd1, &c, 1); printf("c = %c\n", c); // c = f // redirect and now fd2 is now back at f dup2(fd1, fd2); // reading back fd2 which has been redirected, // so c actually becomes o! read(fd2, &c, 1); printf("c = %c\n", c); // c = 0 exit(0); }

The comments in the code explain what is happening in order, but we're just going to print out the result by running gcc one.c && ./a.out. The output binary a.out is the name given since we do not provide output to GCC.

> gcc one.c && ./a.out c = b c = f c = o

To explain further what is going on:

  1. We assign fd1 and fd2 to open foobar.txt.
  2. We use read to read in a character and assign it to variable c.
  3. Each time we read fd2, we move one character further along in the text file.
  4. Eventually, we read fd1 once and then we redirectfd1 to fd2.
  5. We read fd2 one last time, but after redirection the value now reads "o".

A more readable example

The above can seem hard to comprehend - it is better playing around with this stuff in C. This example, I decided to use scanf to read in from stdin in the second example, because I feel like the example was a little clearer for me.

Note: Given I knew the length of the words in the file, I just set a max STR_LEN of 6 as opposed to some dynamic calculation.

Create a file two.c.

#include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <fcntl.h> #define STR_LEN 6 int main() { int fd1; char *c1 = (char*)malloc(STR_LEN); char *c2 = (char*)malloc(STR_LEN); // notice no values printf("c1 = %s\nc2 = %s\n", c1, c2); fd1 = open("foobar.txt", O_RDONLY); // redirect fd1 to stdin if (dup2(fd1, STDIN_FILENO) < 0) { printf("Unable to duplicate file descriptor."); exit(EXIT_FAILURE); } // scan c1 and c2 in from stdin scanf("%s %s", c1, c2); // values now becomes "foobar" and "test" respectively printf("c1 = %s\nc2 = %s\n", c1, c2); // SAVE THE WHALES, FREE THE MALLOCS free(c1); free(c2); exit(0); }

Now if we run gcc two.c && ./a.out, we get the following:

> gcc two.c && ./a.out c1 = c2 = c1 = foobar c2 = test

In this case, we do the following:

  1. Allocate memory for c1 and c2.
  2. Confirm no values in first print.
  3. Read in the foobar.txt file to file descriptor fd1.
  4. Redirect fd1 to stdin.
  5. Use scanf to assign the values to c1 and c2 from stdin.
  6. Confirm with the last print that c1 and c2 have been assigned the words "foobar" and "test" respectively!

Hooray! Redirection to stdin is a success (and no segmentation faults).

I will likely redo this exercise in Rust and Golang this week to show the how-to.

Resources

Image credit: Michael Kubler

Personal image

Dennis O'Keeffe

@dennisokeeffe92
  • Melbourne, Australia

Hi, I am a professional Software Engineer. Formerly of Culture Amp, UsabilityHub, Present Company and NightGuru.
I am currently working on Visibuild.

1,200+ PEOPLE ALREADY JOINED ❤️️

Get fresh posts + news direct to your inbox.

No spam. We only send you relevant content.

Unix Redirection In C

Introduction

Share this post