在之前的该系列的部分中,你学习了有关目录和访问目录的权限是如何工作的。你在这些文章中学习的大多数内容都可应用于文件,除了如何让一个文件变成可执行文件。
因此让我们在开始之前先解决这个问题。
不需要 .exe 扩展名
在其他操作系统中,一个文件的性质通常由它的后缀决定。如果一个文件有一个 .jpg 扩展,操作系统会认为它是一幅图像;如果它以 .wav 结尾,它是一个音频文件;如果它在文件名末尾以 .exe 结尾,它就是一个你可以执行的程序。
这导致了严重的问题,比如说木马可以伪装成文档文件。幸运的是,在 Linux 下事物不是这样运行的。可以确定的是,你可能会看到有些可执行文件是以 .sh 结尾暗示它们是可执行的脚本,但是这大部分是为了便于人眼找到文件,就像你使用 ls --color
将可执行文件的名字以亮绿色显示的方式相同。
事实上大多数应用根本没有扩展名。决定一个文件是否是一个真正程序的是 x
(指可执行的)位。你可以通过运行以下命令使任何文件变得可执行,
chmod a x some_program
而不管它的扩展名是什么或者是否存在。在上面命令中的 x
设置了 x
位,a
说明你为所有用户设置它。你同样可以为一组用户设置成拥有这个文件(g x
),或者只为一个用户——拥有者——设置 (u x
)。
尽管我们会在该系列之后的部分包含从命令行创建和运行脚本的内容,并学习通过输入它的路径并在结尾加上程序名的方式运行一个程序:
代码语言:javascript复制path/to/directory/some_program
或者,如果你当前在相同目录,你可以使用:
代码语言:javascript复制./some_program
还有其他方式可以使你的程序在目录树的任意位置运行 (提示:查询 $PATH
环境变量),但是当我们讨论 shell 脚本的时候你会读到这些。
复制、移动、链接
明显地,从命令行修改和处理文件有很多的方式,而不仅仅是处理它们的权限。当你试图打开一个不存在的文件是,大多数应用会创建一个新文件。如果 test.txt
当前并不存在,下列命令:
nano test.txt
vim test.txt
(nano 和 vim 是流行的命令行文本编辑器)都将为你创建一个空的 test.txt
文件来编辑。
你可以通过 “触摸” (touch
)来创建一个空的文件,
touch test.txt
会创建一个文件,但是不会在任何应用中打开它。
你可以使用 cp
来拷贝一个文件到另一个位置,或者使用一个不同的名字:
cp test.txt copy_of_test.txt
你也可以拷贝一堆文件:
代码语言:javascript复制cp *.png /home/images
上面的命令拷贝当前目录下的所有 PNG 文件到相对你的主目录下的 images/
目录。在你尝试之前 images/
目录必须存在, 不然 cp
将显示一个错误。同样的,警惕,当你复制一个文件到一个已经包含相同名字的文件的目录时,cp
会静默地用新文件覆盖老的文件。
你可以使用:
代码语言:javascript复制cp -i *.png /home/images
如果你想要 cp
命令在有任何危险时警告你 (-i
选项代表交互式的)。
你同样可以复制整个目录,但是为了做到这样,你需要 -r
选项:
cp -rv directory_a/ directory_b
-r
选项代表递归,意味着 cp
会向下探索目录 directory_a
,复制所有的文件和子目录下内部包含的。我个人喜欢包含 -v
选项,因为它使 cp
冗长而啰嗦,意味着它会显示你当前它正在做什么而不是仅仅静默的复制然后存在。
mv
命令移动东西。也就是说,它移动文件从一个位置到另一个位置。最简单的形式,mv
表现的更像 cp
:
mv test.txt new_test.txt
上面的命令使 new_test.txt
出现,test.txt
消失。
mv *.png /home/images
移动当前目录下所有的 PNG 文件到相对于你的主目录的 images/
目录。同样的你必须小心你没有意外的覆盖已存在的文件。使用
mv -i *.png /home/images
如果你想站在安全的角度,你可以使用与 cp
相同的方式。
除了移动与拷贝的不同外,另一个 mv
和 cp
之间的不同是当你移动目录时:
mv directory_a/ directory_b
不需要添加递归的标志。这是因为你实际做的是重命名一个目录,与第一个例子相同,你做的是重命名文件。实际上,即使你从一个目录到另一个目录 “移动” 一个文件,只要两个目录在相同的存储设备和分区,你就是在重命名文件。
你可以做一个实验来证明。 time
是一个工具来让你测量一个命令花费多久来执行。找一个非常大的文件,可以是几百 MB 甚至 几 GB (例如一个长视频),像下方这样尝试拷贝到另一个目录:
$ time cp hefty_file.mkv another_directory/
real 0m3,868s
user 0m0,016s
sys 0m0,887s
下面是 time
的输出。需要关注的是第一行, real 时间。它花费了几乎 4 秒来拷贝 355 MB 的 hefty_file.mkv
到 another_directory/
目录。
现在让我们尝试移动它:
代码语言:javascript复制$ time mv hefty_file.mkv another_directory/
real 0m0,004s
user 0m0,000s
sys 0m0,003s
移动几乎是瞬时的!这是违反直觉的,因为看起来 mv
必须复制这个文件然后删除原来的。这是 mv
对比 cp
命令必须做的两件事。但是,实际上,mv
快了 1000 倍。
这是因为文件系统结构中,它的所有目录树,只为了让用户便利而存在。在每个分区的开始,有一个称作分区表的东西告诉操作系统在实际的物理磁盘上去哪找每个文件。在磁盘上,数据没有分为目录甚至是文件。作为替代的是轨道、扇区和簇。当你在相同分区 “移动” 一个文件时,操作系统实际做的仅仅是在分区表中改变了那个文件的入口,但它仍然指向磁盘上相同的簇信息。
是的!移动是一个谎言!至少在相同分区下是。如果你试图移动一个文件到一个不同的分区或者不同的设备, mv
仍然很快,但可以察觉到它比在相同分区下移动文件慢了。这是因为实际上发生了复制和清除数据。
重命名
有几个不同的命令行 rename
工具。没有一个像 cp
和 mv
那样固定,并且它们工作的方式都有一点不同,相同的一点是它们都被用来改变文件名的部分。
在 Debian 和 Ubuntu 中, 默认的 rename
工具使用 正则表达式(字符组成的字符串模式)来大量的改变目录中的文件。命令:
rename 's/.JPEG$/.jpg/' *
将改变所有扩展名为 JPEG
的文件为 jpg
。文件 IMG001.JPEG
变成 IMG001.jpg
、 my_pic.JPEG
变成 my_pic.jpg
,等等。
另一个 rename
版本默认在 Manjaro 上可获得,这是一个 Arch 的衍生版,更简单,但是可能没有那么强大:
rename .JPEG .jpg *
这和你之前看到的上面做相同的重命名操作。在这个版本,.JPEG
是你想改变的字符组成的字符串,.jpg
是你想要改变成为的,*
表示当前目录下的所有文件。
基本原则是如果你所做的仅仅是重命名一个文件或者目录,你最好用 mv
,这是因为 mv
在所有分发版上都是可靠一致的。