A utility to swap two files While I have never had to swap two files I have always wondered if there was command for swapping two files and recently I decided to see if there was one. Eventually I found out that there wasn't one and as a result I decided to create one.
Here is the code: main.cc
#include &lt;iostream&gt;
#include &lt;filesystem&gt;
#include &lt;cstring&gt;
#include &lt;cassert&gt;

static auto print_help() -&gt; void {
    std::cout &lt;&lt; &quot;Usage: swap [file1] [file2]\n&quot;;
    std::cout &lt;&lt; &quot;swaps the contents of file1 and file2\n&quot;;
    std::cout &lt;&lt; &quot;use swap --help to print this message\n&quot;;
}

static auto validate_files(const std::filesystem::path&amp; file1_path, const std::filesystem::path&amp; file2_path) -&gt; void {
    {
        /* check if file exists */
        const auto file1_exists = std::filesystem::exists(file1_path);
        const auto file2_exists = std::filesystem::exists(file2_path);
        const auto exists = file1_exists &amp;&amp; file2_exists;


        if (!exists) {
            if (!file1_exists) std::cerr &lt;&lt; &quot;cannot find file &quot; &lt;&lt; file1_path &lt;&lt; '\n';
            if (!file2_exists) std::cerr &lt;&lt; &quot;cannot find file &quot; &lt;&lt; file2_path &lt;&lt; '\n';
            exit(EXIT_FAILURE);
        }
    }

    {
        if (file1_path == file2_path) {
            std::cerr &lt;&lt; &quot;swaping the same two files does nothing\n&quot;;
            exit(EXIT_SUCCESS);
        }
    }
}

static auto get_temp_filename(char* template_name) -&gt; void {
    /* tmpnam_s does not work on linux */
#if defined(WIN32) || defined(_WIN32)
    errno_t err = tmpnam_s(template_name, L_tmpnam);
    assert(!err);
#else
    int err = mkstemp(template_name);
    assert(err != -1);
#endif
}

int main(int argc, char** argv) {
    std::ios::sync_with_stdio(false);
    switch (argc) {
        case 2: {
            /* convert the second arg to upper case */
            std::transform(argv[1],
                argv[1] + strlen(argv[1]),
                argv[1],
                ::toupper);
            if (!strcmp(argv[1], &quot;--HELP&quot;)) {
                print_help();
                return EXIT_SUCCESS;
            }
            else {
                std::cerr &lt;&lt; &quot;Invalid args see --help for usage\n&quot;;
                return EXIT_FAILURE;
            }
        }
        case 3:
            break;
        default: {
            std::cerr &lt;&lt; &quot;Invalid args see --help for usage\n&quot;;
            return EXIT_FAILURE;
        }
    }
    const auto file1_path = std::filesystem::path{ argv[1] };
    const auto file2_path = std::filesystem::path{ argv[2] };


    validate_files(file1_path, file2_path);
    char temp_filename[L_tmpnam] = &quot;XXXXXX&quot;;
    get_temp_filename(temp_filename);
    const auto temp_filepath = std::filesystem::path{ temp_filename };
    /* move-swap the files instead of copy-swaping */
    /* renaming a file is the same as moving it */
    std::filesystem::rename(file1_path, temp_filepath);
    std::filesystem::rename(file2_path, file1_path);
    std::filesystem::rename(temp_filepath, file2_path);
}

Here is an example of usage:
swap doc1.txt doc2.txt
file1_path == file2_path surely tells that paths refer to the same file. However, even if file1_path != file2_path they still may refer to the same file.

file1_exists = std::filesystem::exists(file1_path); introduces a TOC-TOU race condition. The file may exist at the time of test, yet disappear by the time of use. See the next bullet.

std::filesystem::rename may fail. You call it tree times. If the second, or third call fails (with an exception!), the filesystem ends up not exactly in a state one would expect. Use a noexcept overload, test the error_code after each call, and roll back all actions prior to failure. That would also automagically take care of the nonexistent paths.

Do not assert. It is only good to catch bugs, not the runtime problems. In the production code (compiled with -DNDEBUG) it does nothing, and your program wouldn't detect an mkstemp failure.

The program silently does nothing if called with, say, 4 arguments. It also takes so much effort if called with 2 arguments. Calling print_help() any time argc != 3 is much more straightforward.