1. Overview

Linux provides many handy commands that allow us to manipulate files.

In this quick tutorial, we’ll discuss how to swap two files in the Linux command line.

2. Introduction to the Problem

First of all, let’s clarify what “swapping two files” means. Here, we’re not talking about swapping the location of the two files. Instead, we’ll swap two files’ content.

An example may help us to understand the problem quickly. Let’s say we have two files lying in two different directories:

$ head /home/kent/test/**/*.txt
==> /home/kent/test/dir1/file1.txt <==
I am file1

==> /home/kent/test/dir2/file2.txt <==
I am file2

Now, after swapping the two files, we would like to have:

==> /home/kent/test/dir1/file1.txt <==
I am file2

==> /home/kent/test/dir2/file2.txt <==
I am file1

Note that the contents of two files have been exchanged.

It’s not a hard job, but we’ll address efficient and safe ways to do it.

3. Using the mv Command

As we’ve known, the common way to exchange the values of two variables in many programming languages is to use a temp variable:

temp = a
a = b
b = temp

Similarly, we can take the same idea to swap files. However, we’ll use a temporary file instead of a temp variable and use the mv command as the “assignment” operation:

mv FILE1 TMP
mv FILE2 FILE1
mv TMP FILE2

The three steps are pretty straightforward. However, there are a couple of things we need to note:

  • The location to store the TMP file
  • If an error occurred in any step, we shouldn’t lose data

Next, let’s take a closer look at the two items.

Our intuition may lead us to the /tmp directory when we talk about creating temp files. As its name implies, it’s exactly a nice place to store temp files.

However, any user can access the files under the /tmp directory. Therefore, if we put a file with sensitive data there, we’ll have security risks, especially on a public server. To prevent this from happening, we can save the TMP file in the same location of FILE1 or FILE2. Thus, it can only be accessed by the users who can access FILE1 or FILE2. So, there is no security risk.

The three mv commands won’t work in an atomic way. That is to say, if any of them fail, no rollback operation will be triggered. We can accept it since it’s not a transactional operation anyway. However, our bottom line is no data is lost in error cases.

For example, when we first create TMP under FILE1‘s directory, it may fail due to some IO failure. In this case, we don’t want further commands to cause unexpected file overwriting. To achieve that, we can concatenate the commands with “*&&*“. This is because the && operator ensures the later command gets executed only if the preceding command succeeds.

Now, let’s give it a test on our example:

$ mv /home/kent/test/dir1/file1.txt /home/kent/test/dir1/tmp.file1 && \
    mv /home/kent/test/dir2/file2.txt /home/kent/test/dir1/file1.txt && \
    mv /home/kent/test/dir1/tmp.file1 /home/kent/test/dir2/file2.txt

$ head /home/kent/test/**/*.txt
==> /home/kent/test/dir1/file1.txt <==
I am file2

==> /home/kent/test/dir2/file2.txt <==
I am file1

As the output above shows, the command works. We’ve swapped the content of the two files.

However, the drawback is obvious: we need to type the whole command manually. Since the temp file that we’re about to create doesn’t exist, the auto-completion won’t help us to complete the filename. If we had typos there, some files could be lost.

Therefore, let’s create a function to wrap the long command.

4. Creating a Reusable Function

Ideally, the function can take two arguments, which are the two files’ absolute paths. Further, it should generate the temp file automatically:

function swapFiles() {
    if (( $# == 2)) ; then
        TMPFILE=$(mktemp $(dirname "$1")/XXXXXX)
        mv "$1" $TMPFILE && mv "$2" "$1" && mv $TMPFILE "$2"
    else
        echo "Error: Two valid file paths required"
        return 1
    fi
}

Now, let’s source the function and test if it works:

$ head /home/kent/test/**/*.txt
==> /home/kent/test/dir1/file1.txt <==
I am file1

==> /home/kent/test/dir2/file2.txt <==
I am file2

$ swapFiles /home/kent/test/dir1/file1.txt /home/kent/test/dir2/file2.txt

$ head /home/kent/test/**/*.txt
==> /home/kent/test/dir1/file1.txt <==
I am file2

==> /home/kent/test/dir2/file2.txt <==
I am file1

As we can see from the output above, our function works as expected.

Also, we can just give the two files we want to swap as arguments. The function will handle all the rest. In this case, Bash’s auto-completion will help us a lot.

Next, let’s walk through the function quickly to understand how it works:

  • We’ve used the mktemp command to create a temp file with a random name.
  • To ensure the temp file is in the same directory as the first input file, we’ve used the dirname “$1” command to get the first file’s parent directory.

It’s worth mentioning that in the function, for simplicity, we’ve just checked that the number of arguments is two. We didn’t check if the two arguments are valid files.

5. Conclusion

We’ve learned how to swap two files’ content using three mv commands in this article.

Further, we’ve created a function so that we can perform this operation conveniently.