Linux下进行文件的解压、复制、移动应该是最常见的操作了。尤其是我们在项目中使用大量的数据集文件(比如机器学习)时。然而使用这些命令时一不留神就会掉进坑里,这篇文章我们就来细数用Shell进行文件操作的这些坑。
将文件单个地进行压缩与解压
Linux下压缩文件的常见扩展名包括 .gz
, .tar
, .tar.gz
, .zip
等。这些压缩格式都能够跨平台(Windows/Mac/Linux)使用。下面我们以 .zip
文件为例子来讲解。我们已知一个文本文件压缩包 test.zip
,想把它解压,很简单,运行 unzip
命令即可:
orion-orion@MacBook-Pro Learn-Linux % unzip test.zip
Archive: test.zip
inflating: test.txt
如果我们想要将 test.txt
重新压缩呢?你可能情不自禁会执行 zip test.txt
,然后我们发现提示:
orion-orion@MacBook-Pro Learn-Linux % zip test.txt
zip warning: missing end signature--probably not a zip file (did you
zip warning: remember to use binary mode when you transferred it?)
zip warning: (if you are trying to read a damaged archive try -F)
zip error: Zip file structure invalid (test.txt)
其实是传参数传错了,导致 zip
误把 test.txt
当成压缩后的文件名了,这当然不是合法的。我们看 zip
的参数构成:
zip [-options] [-b path] [-t mmddyyyy] [-n suffixes] [zipfile list] [-xi list]
[-b path]
是压缩后的 .zip
文件的路径, zipfile list
是待压缩的文件列表。于是,我们这样写即可成功压缩:
orion-orion@MacBook-Pro Learn-Linux % zip test2.zip test.txt
adding: test.txt (stored 0%)
当然, zip
也支持将多个文件压缩:
orion-orion@MacBook-Pro Learn-Linux % zip test3.zip test.txt test2.txt
adding: test.txt (stored 0%)
adding: test2.txt (stored 0%)
此时我们发现再解压 test3.zip
会发现重新得到了两个原始文件:
orion-orion@MacBook-Pro Learn-Linux % unzip test3.zip
Archive: test3.zip
extracting: test.txt
extracting: test2.txt
zip
也支持对目录压缩,如我们尝试压缩 test
目录:
orion-orion@MacBook-Pro Learn-Linux % zip test4.zip test
adding: test/ (stored 0%)
此时再解压 test4.zip
则会重新生成 test
目录:
orion-orion@MacBook-Pro Learn-Linux % unzip test4.zip
Archive: test4.zip
creating: test/
不过, zip
是将输入的文件列表 分别进行压缩的操作,即是对目录来进行压缩也是对目录内的所有文件one-by-one的操作。那我们需要将很多文件先打包成一个文件,然后再压缩呢?此时就要用到 tar
了。
tar:打包命令
很多人误解 tar
是个压缩命令,其实压缩命令是 gzip
、 xz
以及我们上文提到的 zip
这些。 tar
是个打包命令,只不过附带压缩与解压的功能。 tar
的选项多如牛毛,为了减轻大家的记忆负担,我们只介绍下面两个选项:
-c
: 建立打包文件(可搭配 -v
将过程中打包的文件可视化);
-x
:解包或解压缩的功能(可搭配 -C
在特定目录解压);
(其实还有表示通过gzip进行压缩/解压缩的 -z
,通过bzip2的支持进行压缩/解压缩的 -j
,通过xz的支持进行压缩解压缩的 -J
等,但我们这里统一用 .zip
示范,就省去这些参数了)
因此,我们只需记住以下命令:
[En]
So, we just need to remember the following command:
压缩: tar -cv -f filename.zip 要被压缩的文件或目录名称
解压缩: tar -xv -f filename.zip -C 欲解压的目录(这个目录必须已经存在)
注意,压缩传参顺序是压缩后的.zip文件在前,压缩前的文件在后,别搞错了。(让人联想到gcc编译器,不过 gcc
传参时规定是 -o output_file.out
的形式来指定输出的可执行文件,就回避了这个顺序问题)
比如,我们要将 test
文件夹(该文件夹下有一个 test.txt
文件)压缩,可以运行如下命令:
orion-orion@MacBook-Pro Learn-Linux % tar -cv -f test4.zip test
a test
a test/test.txt
然后将其解压缩到当前目录并运行以下命令:
[En]
Then extract it to the current directory and run the following command:
orion-orion@MacBook-Pro Learn-Linux % tar -xv -f test4.zip -C .
x test/
x test/test.txt
对多个文件压缩:
orion-orion@MacBook-Pro Learn-Linux % tar -cv -f test3.zip test.txt test2.txt
a test.txt
a test2.txt
然后将其解压缩到当前目录:
[En]
Then extract it to the current directory:
orion-orion@MacBook-Pro Learn-Linux % tar -xv -f test3.zip -C .
x test.txt
x test2.txt
由上面所说, zip
/ unzip
和 tar
都是压缩什么解压出来就是什么,原来是目录就是目录,原来没目录不会帮你自动生成一个目录,但Linux或Mac系统的可视化压缩工具就不一样了(在Mac中被称为「归档实用工具」)。Mac中对目录压缩时压缩命令和 tar
命令是等效的,比如我们想用Mac自带的压缩工具压缩 test
文件夹:
会生成对应的归档文件:
如果您解压缩它,您将得到相同的文件夹(它将自动重命名我们),这不会帮助我们生成额外的目录:
[En]
If you unzip it, you will get the same folder (it will automatically rename us), which will not help us generate extra directories:
然而,如果我们尝试用Mac自带的压缩工具压缩多个文件:
它会自动帮我们生成一个名为 归档.zip
的文件:
然后,如果此时我们尝试对 归档.zip
文件进行解压,会发现 系统会自动帮我们生成一个名为 归档
的文件夹:
在此文件夹中是我们需要的文件:
[En]
Inside this folder is the file we need:
这在对大量文件操作时需要额外注意,否则会白白开销你一次拷贝文件的时间!
文件拷贝
我们紧接上面的情景。假设我们当前的目录为项目目录,而我们手滑使用了系统自带的可视化解压工具生成了一个多余的目录。我们接下来要把系统生成的多余的 归档
文件夹里的文件拷贝到当前目录,那么我们可以使用带 r
参数的 cp
命令:
orion-orion@MacBook-Pro Learn-Linux % cp -r 归档/ .
orion-orion@MacBook-Pro Learn-Linux % ls
test.txt test2.txt 归档
这里 -r
参数表示递归复制命令,用于目录的递归复制。注意命令中的 归档/
表示 归档
目录下的所有文件,意思和 归档/*
相同:
orion-orion@MacBook-Pro Learn-Linux % cp -r 归档/* .
orion-orion@MacBook-Pro Learn-Linux % ls
test.txt test2.txt 归档
选项参数 -r
写成 -R
是等效的:
orion-orion@MacBook-Pro Learn-Linux % cp -R 归档/* .
orion-orion@MacBook-Pro Learn-Linux % ls
test.txt test2.txt 归档
但如果直接传入参数 归档
,则表示将这个目录整个地复制:
orion-orion@MacBook-Pro Learn-Linux % cp -r 归档 .
cp: ./归档 and 归档 are identical (not copied).
同一目录中不可能有两个同名的子目录,这当然会出错,当然我们也可以将其复制到另一个目录中:
[En]
It is impossible to have two subdirectories with the same name in the same directory, which, of course, will go wrong, and of course we can copy it to another directory:
orion-orion@MacBook-Pro Learn-Linux % cp -r 归档 /tmp
orion-orion@MacBook-Pro Learn-Linux % ls /tmp |grep 归档
归档
你可能要问,加 r
和不加 r
有啥区别?如果不加 r
,则默认是跳过目录的,也就是说只能copy文件:
orion-orion@MacBook-Pro Learn-Linux % cp 归档/ .
cp: 归档/ is a directory (not copied).
orion-orion@MacBook-Pro Learn-Linux % cp 归档 /tmp
cp: 归档 is a directory (not copied).
文件移动
我们还是紧接着上面的场景。假定我们已经将 归档
文件夹中的 test.txt
、 test2.txt
成功拷贝到当前项目目录了。现在我们有了个新的需求:我们在项目目录中建了一个 data
子目录,现在需要将项目目录中的 test.txt
、 test2.txt
移动到 data
子目录中。这就需要如下命令:
orion-orion@MacBook-Pro Learn-Linux % mv test2.txt test.txt data
orion-orion@MacBook-Pro Learn-Linux % ls data
test.txt test2.txt
注意,如果有多个源文件或目录,则最后一个目标文件(也就是这里的data)一定是目录。当我们只移动一个文件时,就有潜在的二义性。这里因为 data
目录本身存在,我们移动 test.txt
到 data
目录还能正常执行:
orion-orion@MacBook-Pro Learn-Linux % mv test.txt data
orion-orion@MacBook-Pro Learn-Linux % ls data
test.txt
但是如果data目录不存在,就会将 mv
解释为重命名的意思,比如如果我们将 data
目录删除再执行:
orion-orion@MacBook-Pro Learn-Linux % mv test.txt data
此时就等效于把 test.txt
更名为 data
文件:
orion-orion@MacBook-Pro Learn-Linux % ls -l|grep data
-rw-r--r-- 1 orion-orion staff 0 4 20 22:01 data
可以看出,第一个字母是 -
,也就意味着 data
是普通文件,不是目录(是目录的话第一个字母是 d
)。
因此,使用 mv
语句时要格外小心,因为它既有移动到目录的作用,也有重命名的作用,一不注意就可能出错!
Original: https://www.cnblogs.com/orion-orion/p/16172070.html
Author: orion-orion
Title: Linux:文件解压、复制和移动的若干坑
原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/523786/
转载文章受原作者版权保护。转载请注明原作者出处!