Linux 上提供的点击式图形用户界面非常棒……但如果你的首选交互式开发环境由终端窗口、Bash、Vim 和你喜欢的语言编译器组成,那么,像我一样,你会经常使用终端。
但即使是通常避免使用终端的人,也可以通过更多地了解其环境提供的丰富功能而受益。一个典型的例子就是 cp 命令。根据维基百科,cp (或 copy)命令是 Unix 版本 1 的一部分。与一组精选的其他命令——ls、mv、cd、pwd、mkdir、vi、sh、sed 和 awk 浮现在脑海——一样,cp 是我在 1984 年在 System V Unix 中迈出的最初几步之一。cp 最常见的用途是复制文件,例如
cp sourcefile destfile
在终端会话的命令提示符下发出。上面的命令将名为 sourcefile 的文件复制到名为 destfile 的文件。如果 destfile 在命令发出之前不存在,则会创建它;如果它确实存在,则会被覆盖。
我不知道我使用过这个命令多少次(也许我不想知道),但我知道当我编写和测试代码并且有一个工作版本的东西想要在继续之前保持原样时,我经常使用它。所以,在过去的 30 多年里,我可能至少在命令提示符下输入过这样的内容
cp test1.py test1.bak
至少一万亿次。或者,我可能已决定继续进行我的测试程序的版本 2,在这种情况下,我可能已键入
cp test1.py test2.py
来完成该移动的第一步。
这是一件如此常见和简单的事情,以至于我很少查看 cp 的参考文档。但是,在备份我的 Pictures 文件夹(在我的 GUI 环境中使用 Files 应用程序)时,我开始思考,“我想知道是否有一个选项可以让 cp 仅复制新文件或已更改的文件?” 当然,确实有!
绝佳用法 #1:更新文件夹的第二个副本
假设我的计算机上有一个文件夹,其中包含一系列文件。此外,假设我不时地将新文件放入该集合中。最后,假设我不时地可能会以某种方式编辑这些文件中的一个。此类集合的一个示例可能是我从手机或音乐文件中下载的照片。
假设此文件集合对我具有持久的价值,我可能偶尔想制作它的副本——它的一种“快照”——以将其保存在其他介质上。当然,存在许多用于执行备份的实用程序,但也许我希望在可移动设备上复制此确切结构,我通常将其离线存储,甚至连接到另一台计算机。
cp 命令提供了一种非常简单的方法来做到这一点。这是一个例子。
在我的 Pictures 文件夹中,我有一个名为 Misc 的子文件夹。为了说明目的,我将在 USB 记忆棒上复制它。我们开始吧!
me@desktop:~/Pictures$ cp -r Misc /media/clh/4388-D5FE
me@desktop:~/Pictures$
以上行是从我的终端窗口按原样复制的。对于那些可能不太熟悉该环境的人来说,值得注意的是 me @mydesktop:~/Pictures$ 是终端在每次输入和执行命令之前提供的命令提示符。它标识用户 (me)、计算机 (mydesktop) 和当前工作目录,在本例中为 ~/Pictures,它是 /home/me/Pictures 的简写,即我的主目录中的 Pictures 文件夹。
我输入并执行的命令 cp -r Misc /media/clh/4388-D5FE 将文件夹 Misc 及其所有内容(-r 或“recursive”选项指示内容以及文件夹或文件本身)复制到文件夹 /media/clh/4388-D5FE 中,这是我的 USB 记忆棒的挂载位置。
执行该命令使我返回到原始提示符。与从 Unix 继承的大多数命令一样,如果命令执行时没有检测到任何类型的异常结果,它就不会在终止之前打印出类似“执行成功”的消息。想要更多反馈的人可以使用 -v 选项使执行“verbose”。
下面是我的 Misc 新副本在 USB 驱动器上的图像。该目录中有九个 JPEG 文件。

opensource.com
假设我在目录 ~/Pictures/Misc 的主副本中添加了一些新文件,现在它看起来像这样

opensource.com
现在我想仅将新文件复制到我的记忆棒上。为此,我将使用 cp 的“update”和“verbose”选项
me@desktop:~/Pictures$ cp -r -u -v Misc /media/clh/4388-D5FE
'Misc/asunder.png' -> '/media/clh/4388-D5FE/Misc/asunder.png'
'Misc/editing tags guayadeque.png' -> '/media/clh/4388-D5FE/Misc/editing tags guayadeque.png'
'Misc/misc on usb.png' -> '/media/clh/4388-D5FE/Misc/misc on usb.png'
me@desktop:~/Pictures$
上面的第一行显示了 cp 命令及其选项(-r 代表“recursive”,-u 代表“update”,-v 代表“verbose”)。接下来的三行显示了复制过来的文件。最后一行再次显示命令提示符。
一般来说,诸如 -r 之类的选项也可以以更详细的方式给出,例如 --recursive。简短形式也可以组合,例如 -ruv。
绝佳用法 #2 – 制作版本化备份
回到我最初的示例,即定期备份开发中代码的工作版本,我在学习 update 时发现的另一个非常有用的 cp 选项是 backup。
假设我打算编写一个非常有用的 Python 程序。作为迭代开发的爱好者,我可能会先让程序的简单版本工作,然后逐步向其添加更多功能,直到它完成工作。假设我的第一个版本仅使用 Python print 命令打印字符串“hello world”。这是一个单行程序,如下所示
print 'hello world'
我已将该字符串放入文件 test1.py 中。我可以从命令行运行它,如下所示
me@desktop:~/Test$ python test1.py
hello world
me@desktop:~/Test$
现在程序可以工作了,我想在添加下一个组件之前对其进行备份。我决定使用带编号的备份选项,如下所示
clh@vancouver:~/Test$ cp --force --backup=numbered test1.py test1.py
clh@vancouver:~/Test$ ls
test1.py test1.py.~1~
clh@vancouver:~/Test$
那么,这一切意味着什么呢?
首先,--backup=numbered 选项表示,“我想进行备份,并且我希望连续备份进行编号。” 因此,第一个备份将是编号 1,第二个是 2,依此类推。
其次,请注意源文件和目标文件是相同的。通常,如果我们尝试使用 cp 命令将文件复制到自身,我们将收到类似
cp: 'test1.py' and 'test1.py' are the same file
在我们要进行备份并且我们想要相同的源和目标文件的特殊情况下,我们使用 --force 选项。
第三,我使用了 ls (或“list”)命令来显示我们现在有一个名为 test1.py 的文件,它是原始文件,另一个名为 test1.py.~1~ 的文件,它是备份文件。
假设现在我要添加到程序的第二个功能是另一个打印语句,该语句打印字符串“Kilroy was here。” 现在文件 test1.py 中的程序看起来像这样
print 'hello world'
print 'Kilroy was here'
看看 Python 编程是多么简单?无论如何,如果我再次执行备份步骤,这就是发生的事情
clh@vancouver:~/Test$ cp --force --backup=numbered test1.py test1.py
clh@vancouver:~/Test$ ls
test1.py test1.py.~1~ test1.py.~2~
clh@vancouver:~/Test$
现在我们有两个备份文件:test1.py.~1~,其中包含原始的单行程序,以及 test1.py.~2~,其中包含两行程序,我可以继续添加和测试更多功能。
对我来说,这是一件非常有用的事情,我正在考虑制作一个 shell 函数来使其更简单。
总结三点
首先,默认安装在大多数桌面和服务器发行版上的 Linux 手册页提供了诸如 cp 之类的命令的详细信息和偶尔有用的示例。在终端中,输入命令
man cp
对于那些刚开始学习如何使用命令的用户来说,这些解释可能既晦涩又难以理解。对于那些倾向于坚持不懈的人,我建议创建一个测试目录和文件,并在那里尝试命令和选项。
其次,如果教程更受关注,那么在您喜欢的搜索引擎中键入搜索字符串“linux shell tutorial”会带来许多有趣且有用的资源。
第三,如果您想知道,“当 GUI 通常以点击式的轻松方式提供相同的功能时,为什么要费心?” 我有两个回应。第一个是“点击式”并不总是那么容易,尤其是在它扰乱另一个工作流程并需要大量的点击才能使其工作时。第二个是通过使用 shell 脚本、shell 函数和 shell 别名,通常可以轻松地简化重复性任务。
您是否以新的或有趣的方式使用 cp 命令?请在评论中告诉我们。
13 条评论