Contents

在Linux命令行中交换两个文件

1. 概述

Linux 提供了许多方便的命令,允许我们操作文件。 在这个快速教程中,我们将讨论如何在 Linux 命令行中交换两个文件。

2. 问题介绍

首先,让我们澄清一下“交换两个文件”是什么意思。在这里,我们不是在谈论交换两个文件的位置。相反,我们将交换两个文件的内容

一个例子可以帮助我们快速理解问题。假设我们有两个文件位于两个不同的目录中:

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

现在,在交换两个文件之后,我们想要:

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

请注意,两个文件的内容已交换。

这不是一项艰巨的工作,但我们将解决有效和安全的方法来做到这一点。

3. 使用mv命令

正如我们所知,在许多编程语言中交换两个变量值的常用方法是使用临时变量

temp = a
a = b
b = temp

同样,我们也可以采用同样的思路来交换文件。但是,我们将使用临时文件而不是temp变量,并使用mv 命令作为“赋值”操作:

mv FILE1 TMP
mv FILE2 FILE1
mv TMP FILE2

这三个步骤非常简单。但是,有几点我们需要注意

  • 存储TMP文件的位置
  • 如果任何步骤发生错误,我们不应该丢失数据

接下来,让我们仔细看看这两个项目。

当我们谈论创建临时文件时,我们的直觉可能会将我们带到*/tmp*目录。顾名思义,它正是存储临时文件的好地方。

但是,任何用户都可以访问 /tmp 目录下的文件。因此,如果我们将包含敏感数据的文件放在那里,我们将面临安全风险,尤其是在公共服务器上。为了防止这种情况发生,我们可以将TMP文件保存在FILE1FILE2的相同位置。因此,它只能由可以访问FILE1FILE2 的用户访问。因此,不存在安全风险。

三个mv命令不会以原子方式工作。也就是说,如果其中任何一个失败,则不会触发回滚操作。我们可以接受它,因为它无论如何都不是事务操作。但是,我们的底线是在错误情况下不会丢失任何数据。

例如,当我们第一次在FILE1的目录下创建TMP时,它可能由于某些 IO 失败而失败。在这种情况下,我们不希望进一步的命令导致意外的文件覆盖。为此,我们可以将命令与“ && ”连接起来。这是*因为*&&运算符确保只有在前面的命令成功时才会执行后面的命令

现在,让我们对我们的示例进行测试:

$ 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

如上面的输出所示,该命令有效。我们交换了这两个文件的内容。

但是,缺点很明显:我们需要手动输入整个命令。由于我们要创建的临时文件不存在,因此自动完成不会帮助我们完成文件名。如果我们有错别字,一些文件可能会丢失。

因此,让我们创建一个函数来包装长命令。

4. 创建一个可重用的函数

理想情况下,该函数可以采用两个参数,即两个文件的绝对路径。此外,它应该自动生成临时文件:

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
}

现在,让我们获取函数并测试它是否有效:

$ 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

从上面的输出可以看出,我们的函数按预期工作。

此外,我们可以只给出我们想要交换的两个文件作为参数。该函数将处理所有其余部分。在这种情况下,Bash 的自动补全对我们有很大帮助。

接下来,让我们快速浏览一下该函数以了解其工作原理:

  • 我们使用mktemp 命令创建了一个具有随机名称的临时文件。
  • 为确保临时文件与第一个输入文件位于同一目录中,我们使用*dirname “$1”*命令获取第一个文件的父目录。

值得一提的是,在函数中,为简单起见,我们刚刚检查了参数的数量是两个。我们没有检查这两个参数是否是有效文件。