文件压缩和解压

常用的压缩包后缀有 .tar.gz.bz.z.zip.rar 等,分别采用不同压缩方法进行压缩和解压。根据不同类型可以在 Linux 下选择不同的压缩文件。

gzipgunzip

gzip 命令和 gunzip 命令用于 .gz 文件的压缩和解压。

gzip <参数> <目录> 可用于目录的压缩,压缩后得到的文件会放在工作目录。

  • 常用参数:
    • -l:列出压缩文件的相关信息(list)
    • -v:显示指令执行过程(verbose)
    • -d:改为解压指定文件(decompress)
    • -r:递归处理目录下的文件及子目录(recursive)

gunzip <参数> <文件.gz> 可用于文件的解压,解压的目录放在工作目录下。常用参数同上(除 -d)。

bzip2bunzip2

bzip2 命令和 bunzip2 命令用于 .bz2 文件的压缩和解压。

bzip2 <参数> <目录> 可用于目录的压缩,压缩后得到的文件会放在工作目录。常用参数同上。

bunzip2 <参数> <文件.bz2> 可用于文件的解压,解压的目录放在工作目录下。常用参数同上(除 -d)。

compressuncompress

compress 命令和 uncompress 命令用于 .Z 文件的压缩和解压。该方法已不太常用

bzip2 <参数> <目录> 可用于目录的压缩,压缩后得到的文件会放在工作目录。支持同上-v-d 参数。

bunzip2 <参数> <文件.bz2> 可用于文件的解压,解压的目录放在工作目录下。支持同上 -v 参数。

tar

tar 是用来建立,还原备份文件的工具程序,可以加入、解开备份文件内的文件。(tape archive)

tar 本身可以处理 .tar 格式的压缩和解压。但通过附加参数,tar 命令即可实现 tar 上追加其他属性的压缩和解压。

模式参数:

  • -c:建立压缩档案
  • -x:解压
  • -t:查看内容
  • -r:像压缩归档文件末尾追加文件
  • -u:更新原压缩包中的文件

以上五个独立命令是使用 tar 操作时必须用到,指定本次命令的目的。五个参数只能选择其一,并可与其他参数混用。

其他参数:

  • -z:gzip 属性
  • -j:bz2 属性
  • -Z:compress 属性
  • -v:显示所有过程
  • -O:将文件解开到标准输出

必选结尾参数:

  • -f:使用档案名。该参数是最后一个参数,后面接档案名。

示例:

1
2
3
4
5
6
7
8
9
10
11
# 压缩操作
tar –cvf jpg.tar *.jpg # 将目录里所有jpg文件打包成 tar.jpg
tar –czf jpg.tar.gz *.jpg # 将目录里所有jpg文件打包成 jpg.tar 后,并且将其用 gzip 压缩,生成一个 gzip 压缩过的包,命名为 jpg.tar.gz
tar –cjf jpg.tar.bz2 *.jpg # 将目录里所有jpg文件打包成 jpg.tar 后,并且将其用 bzip2 压缩,生成一个 bzip2 压缩过的包,命名为jpg.tar.bz2
tar –cZf jpg.tar.Z *.jpg # 将目录里所有 jpg 文件打包成 jpg.tar 后,并且将其用 compress 压缩,生成一个 umcompress 压缩过的包,命名为jpg.tar.Z

# 解压操作
tar –xvf file.tar # 解压 tar 包
tar -xzvf file.tar.gz # 解压 tar.gz
tar -xjvf file.tar.bz2 # 解压 tar.bz2
tar –xZvf file.tar.Z # 解压 tar.Z

zipunzip

zip 命令和 unzip 命令用于 .zip 文件的压缩。

需要额外注意的是要想使用该命令,需要先安装 Zip for Linux。如在 CentOS 下安装,输入指令:

1
2
$ yum install -y zip
$ yum install -y unzip

用法:zip <参数> [<生成的文件目录>] <目录或多文件>

常用参数:

  • -v:同上
  • -r:同上
  • -d:从压缩文件内删除指定的文件
  • -q:不显示指令执行过程
  • -f:更新现有文件
  • -P <密码>:加密压缩文件,后接加密密码

用法:unzip <参数> <目录或多文件>

常用参数:

  • -v:同上
  • -q:同上
  • -f:同上
  • -P <密码>:解压时输入密码
  • -d <目录>:指定文件解压缩后要存储的目录
  • -x <空格分隔文件>:指定不处理压缩文件中的哪些文件

rarunrar

rar 命令和 unrar 命令用于 .rar 文件的压缩。

需要额外注意的是,要使用该命令同样需要先安装 RAR for Linux。直接 yum 安装可能提示无资源,可以添加其他镜像或直接下载rarunrar 的用法和 zipunzip 类似。

实战:文件压缩和解压

  1. /home/datawhale 目录下昵称文件夹中,下载 https://mirror.coggle.club/dataset/jaychou_lyrics.txt.zip。
  2. 使用 zip 压缩该昵称文件夹
  3. 使用 tar 压缩该昵称文件夹
  4. 将该昵称文件夹打包为 tar.gz 格式

实操:

  1. 下载文件

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    [I have no name!@i-ym8u2kyp MarioZZJ]$ wget https://mirror.coggle.club/dataset/jaychou_lyrics.txt.zip
    --2021-12-27 21:48:35-- https://mirror.coggle.club/dataset/jaychou_lyrics.txt.zip
    Resolving mirror.coggle.club (mirror.coggle.club)... 113.229.252.249, 2408:872b:f01:1002:3::3fc
    Connecting to mirror.coggle.club (mirror.coggle.club)|113.229.252.249|:443... connected.
    HTTP request sent, awaiting response... 200 OK
    Length: 52607 (51K) [application/zip]
    Saving to: ‘jaychou_lyrics.txt.zip’

    100%[==============================================================================>] 52,607 --.-K/s in 0.03s

    2021-12-27 21:48:36 (1.71 MB/s) - ‘jaychou_lyrics.txt.zip’ saved [52607/52607]
  2. zip 压缩目录

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    ## 大家都在根目录执行压缩语句,压缩包全都默认丢到根目录,已经乱成一锅粥了,所以我还是指定一下目标目录
    [I have no name!@i-ym8u2kyp ~]$ zip -v -r ./MarioZZJ/MarioZZJ.zip ./MarioZZJ
    adding: MarioZZJ/ (in=0) (out=0) (stored 0%)
    adding: MarioZZJ/datawhale/ (in=0) (out=0) (stored 0%)
    adding: MarioZZJ/datawhale/affairs.txt (in=92161) (out=14343) (deflated 84%)
    adding: MarioZZJ/datawhale/test.py (in=46) (out=46) (stored 0%)
    adding: MarioZZJ/datawhale/test1.py (in=46) (out=46) (stored 0%)
    adding: MarioZZJ/datawhale/test2.py (in=48) (out=48) (stored 0%)
    adding: MarioZZJ/test5.py (in=188) (out=129) (deflated 31%)
    adding: MarioZZJ/affairs/ (in=0) (out=0) (stored 0%)
    adding: MarioZZJ/affairs/.affairs.py.swp (in=12288) (out=395) (deflated 97%)
    adding: MarioZZJ/affairs/affairs.py (in=241) (out=176) (deflated 27%)
    adding: MarioZZJ/affairs/__init__.py (in=0) (out=0) (stored 0%)
    adding: MarioZZJ/affairs/test6.py (in=173) (out=129) (deflated 25%)
    adding: MarioZZJ/affairs/__pycache__/ (in=0) (out=0) (stored 0%)
    adding: MarioZZJ/affairs/__pycache__/affairs.cpython-36.pyc (in=435) (out=328) (deflated 25%)
    adding: MarioZZJ/affairs/__pycache__/__init__.cpython-36.pyc (in=127) (out=100) (deflated 21%)
    adding: MarioZZJ/test6.py (in=114) (out=92) (deflated 19%)
    adding: MarioZZJ/sleep.py (in=108) (out=91) (deflated 16%)
    adding: MarioZZJ/outlog.txt (in=517740) (out=61794) (deflated 88%)
    adding: MarioZZJ/jaychou_lyrics.txt.zip (in=52607) (out=52607) (stored 0%)
    total bytes=676322, compressed=130324 -> 81% savings
    [I have no name!@i-ym8u2kyp ~]$
  3. tar 压缩目录

    1
    2
    [I have no name!@i-ym8u2kyp ~]$ tar -cf ./MarioZZJ/MarioZZJ.tar ./MarioZZJ
    tar: ./MarioZZJ/MarioZZJ.tar: file is the archive; not dumped

    发现直接这么执行报错了,为什么呢?通过查找资料发现 tar 后接目标时只能写文件名,不能写本例中的目录名。否则只会生成备份文件而非压缩文件。所以我们可以重新操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    [I have no name!@i-ym8u2kyp ~]$ cd MarioZZJ
    [I have no name!@i-ym8u2kyp MarioZZJ]$ rm MarioZZJ.tar
    [I have no name!@i-ym8u2kyp MarioZZJ]$ tar -cvf MarioZZJ.tar * # 打包当前目录下所有文件,可以使用通配符 *
    affairs/
    affairs/.affairs.py.swp
    affairs/affairs.py
    affairs/__init__.py
    affairs/test6.py
    affairs/__pycache__/
    affairs/__pycache__/affairs.cpython-36.pyc
    affairs/__pycache__/__init__.cpython-36.pyc
    datawhale/
    datawhale/affairs.txt
    datawhale/test.py
    datawhale/test1.py
    datawhale/test2.py
    jaychou_lyrics.txt.zip
    MarioZZJ.zip
    outlog.txt
    sleep.py
    test5.py
    test6.py
    [I have no name!@i-ym8u2kyp MarioZZJ]$
  4. 压缩目录为 tar.gz

    1
    2
    [I have no name!@i-ym8u2kyp MarioZZJ]$ tar -czf MarioZZJ.tar.gz *
    [I have no name!@i-ym8u2kyp MarioZZJ]$

文件文本字符查找替换

grep

grep 命令用于查找文件里符合条件的字符串行,即如果发现某文件包含符合指定范本样式的内容,就把那一行显示出来。

用法:grep [-abcEFGhHilLnqrsvVwxy][-A<显示行数>][-B<显示列数>][-C<显示列数>][-e<范本样式>][-f<范本文件>][--help][范本样式][文件或目录...]

参数:

  • -A <显示行数>:除了显示结果行之外并展示该行之后的内容(同 --after-context=<显示行数>
  • -B <显示行数>:除了显示结果行之外并展示该行之前的内容(同 --before-context=<显示行数>
  • -C <显示行数>:除了显示结果行之外并展示该行之前之后的内容(同 --context=<显示行数>
  • -e <范本样式>:指定字符串作为查找文件内容的样式(同 --regexp=<范本样式>),见 正则表达式 – 语法 | 菜鸟教程 (runoob.com)
  • -f <规则文件>:指定规则文件,其内容含有一个或多个规则样式,让 grep 查找符合规则条件的文件内容,格式为每行一个规则样式。
  • -i:忽略字符大小写(同 --ignore-case
  • -l:仅输出符合指定样式的文件名称
  • -n:在显示符合样式的那一行之前,标示出该行的列数编号
  • -r:以递归方式查找符合条件的文献(查找目录及子目录,同 --recursive-d recurse
  • -v:反向查找,打印出不符合条件行的内容(同 --invert-match

应用举例:

系统报警显示了时间,但是日志文件太大无法直接 cat 查看。(查询含有特定文本的文件,并拿到这些文本所在的行)

1
grep -n '2019-10-24 00:01:11' *.log

在当前目录里第一级文件夹中寻找包含指定字符串的 .in 文件

1
grep "thermcontact" /.in

从根目录开始查找所有扩展名为 .log 的文本文件,并找出包含 “ERROR” 的行:

1
find / -type f -name "*.log" | xargs grep "ERROR"

例子:从当前目录开始查找所有扩展名为 .in 的文本文件,并找出包含 “thermcontact” 的行:

1
find . -name "*.in" | xargs grep "thermcontact"

sed

sed 命令可用来自动编辑一个或多个文件,简化对文件的反复操作。

用法:sed [-hnV][-e <script>][-f <script文件>][文本文件]

参数:

  • -e:以选项中指定的 script 处理输入的文本文件
  • -f:以选项中指定的 script 文件来处理输入的文本文件
  • -n:仅显示 script 处理后的结果

动作说明:

  • a:新增, a 的后面接字符串,这些字符串会在新的一行出现
  • c:取代, c 的后面接字符串,这些字符串可以取代 n1,n2 之间的行!
  • d:删除
  • i:插入, i 的后面接字符串,这些字符串会在新的一行出现(目前的上一行)
  • p:打印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行
  • s:取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法

动作举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# 删除某行
sed -e '1d' ab #删除第一行
sed -e '$d' ab #删除最后一行
sed -e '1,2d' ab #删除第一行到第二行
sed -e '2,$d' ab #删除第二行到最后一行

  # 显示某行
sed -e '1p' ab #显示第一行
sed -e '$p' ab #显示最后一行
sed -e '1,2p' ab #显示第一行到第二行
sed -e '2,$p' ab #显示第二行到最后一行

  # 使用模式进行查询
sed -e '/ruby/p' ab #查询包括关键字ruby所在所有行
sed -e '/\$/p' ab #查询包括关键字$所在所有行,使用反斜线\屏蔽特殊含义

  # 增加一行或多行字符串
cat ab
Hello!
ruby is me,welcome to my blog.
end
sed -e '1a drink tea' ab #第一行后增加字符串"drink tea"
Hello!
drink tea
ruby is me,welcome to my blog.
end
sed -e '1,3a drink tea' ab #第一行到第三行后增加字符串"drink tea"
Hello!
drink tea
ruby is me,welcome to my blog.
drink tea
end
drink tea
sed -e '1a drink tea\nor coffee' ab #第一行后增加多行,使用换行符\n
Hello!
drink tea
or coffee
ruby is me,welcome to my blog.
end

#   代替一行或多行
sed -e '1c Hi' ab #第一行代替为Hi
Hi
ruby is me,welcome to my blog.
end
sed -e '1,2c Hi' ab #第一行到第二行代替为Hi
Hi
end

# 替换一行中的某部分
# 格式:sed 's/要替换的字符串/新的字符串/g' (要替换的字符串可以用正则表达式)
sed -n -e '/ruby/p' ab | sed 's/ruby/bird/g' #替换ruby为bird
sed -n -e '/ruby/p' ab | sed 's/ruby//g' #删除ruby

# 插入
sed -i '$a bye' ab #在文件ab中最后一行直接输入"bye"
cat ab
Hello!
ruby is me,welcome to my blog.
end
bye

# 删除匹配行
# 格式:sed -i '/匹配字符串/d' filename (注:若匹配字符串是变量,则需要“”,而不是‘’。)

# 替换匹配行中的某个字符串
# 格式:sed -i '/匹配字符串/s/替换源字符串/替换目标字符串/g' filename

实战:字符串查找替换

  1. /home/datawhale 目录下昵称文件夹中,下载 https://mirror.coggle.club/dataset/jaychou_lyrics.txt.zip,并解压。
  2. 使用 grep 完成下列操作,并输出到屏幕
    1. 统计歌词中 包含【超人】的歌词
    2. 统计歌词中 包含【外婆】但不包含【期待】的歌词
    3. 统计歌词中 以【我】开头的歌词
    4. 统计歌词中 以【我】结尾的歌词
  3. 使用 sed 命令完成下列操作,并输出到屏幕
    1. 将歌词中 第2行 至 第40行 删除
    2. 将歌词中 所有【我】替换成【你】

实操:

  1. 下载文件并解压
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[I have no name!@i-ym8u2kyp MarioZZJ]$ wget https://mirror.coggle.club/dataset/jaychou_lyrics.txt.zip
--2021-12-27 23:45:13-- https://mirror.coggle.club/dataset/jaychou_lyrics.txt.zip
Resolving mirror.coggle.club (mirror.coggle.club)... 113.229.252.249, 2408:872b:f01:1002:3::3fc
Connecting to mirror.coggle.club (mirror.coggle.club)|113.229.252.249|:443... connected.
HTTP request sent, awaiting response... 200 OK
Length: 52607 (51K) [application/zip]
Saving to: ‘jaychou_lyrics.txt.zip’

100%[==============================================================================>] 52,607 --.-K/s in 0.06s

2021-12-27 23:45:13 (880 KB/s) - ‘jaychou_lyrics.txt.zip’ saved [52607/52607]
[I have no name!@i-ym8u2kyp MarioZZJ]$ unzip -d . jaychou_lyrics.txt.zip
Archive: jaychou_lyrics.txt.zip
inflating: ./jaychou_lyrics.txt
  1. grep 文本匹配
1
2
3
4
5
6
[I have no name!@i-ym8u2kyp MarioZZJ]$ grep -n "超人" jaychou_lyrics.txt
5795:如果超人会飞 那就让我在空中停一停歇
5798:不要问我哭过了没 因為超人不能流眼泪
5815:只能说当超人真的好难
5816:如果超人会飞 那就让我在空中停一停歇
5819:不要问我哭过了没 因為超人不能流眼泪
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
[I have no name!@i-ym8u2kyp MarioZZJ]$ grep -n "外婆" jaychou_lyrics.txt | grep -v "期待"
579:我想带你 回我的外婆家
595:我想带你 回我的外婆家
2267:今天是外婆生日
2269:载着外婆开着拉风的古董车兜兜兜风
2274:外婆她脸上的涟漪
2288:外婆她的无奈
2294:记得去年外婆的生日
2295:表哥带我和外婆参加
2304:是因为看到外婆失落而失落
2313:我告诉外婆 我没输 不需要改变
2316:只要外婆觉得好听
2318:外婆露出了笑容 说她以我为荣
2327:外婆她的无奈
2339:外婆她的无奈
1
2
3
4
5
6
7
[I have no name!@i-ym8u2kyp MarioZZJ]$ grep -n -e "^我" jaychou_lyrics.txt
5:我每天每天每天在想想想想著你
24:我每天每天每天在想想想想著你
51:我想要将我的寂寞封闭
### 太多了,略去部分输出
5788:我唱的歌词要有点文化 因為随时会被当教材
5811:我到底是一个创作歌手
1
2
3
4
5
6
7
[I have no name!@i-ym8u2kyp MarioZZJ]$ grep -n -e "我$" jaychou_lyrics.txt
82:随风跟著我
120:你在那里 在小村外的溪边河口默默等著我
132:默默的在等著我
### 太多了,略去部分输出
5361:人群散了后 夜色多朦朧 月光也會跟著我
5365:人群散了后 夜色多朦朧 月光也會跟著我
  1. sed 文本替换
1
2
3
4
5
[I have no name!@i-ym8u2kyp MarioZZJ]$ sed -e '2,40d' jaychou_lyrics.txt
想要有直升机
透明的让我感动的可爱女人
坏坏的让我疯狂的可爱女人
### 省略其余输出
1
2
3
4
5
6
7
8
[I have no name!@i-ym8u2kyp MarioZZJ]$ sed -n -e '/我/p' jaychou_lyrics.txt | sed 's/我/你/g'
你每天每天每天在想想想想著你
让你开始乡相信命运
让你碰到你
漂亮的让你面红的可爱女人
### 太多了,省略部分输出
拯救地球好累 虽然有些疲惫 但你还是会
不要问你哭过了没 因為超人不能流眼泪

文件目录查找

find

find 命令用于在指定目录下查找文件。

用法:find <path> <参数> [-exec <命令> {} \]

参数前的字符串视为欲查找的目录名,如果不指定目录名则在当前目录下查找。

常用参数:

  • -name <文件名>:文件名满足要求的文件。使用 -iname 可以忽略大小写

  • -type <类型>:文件类型满足要求的文件。类型包括:

    • d:目录
    • f:一般文件
    • 其他:cbpls
  • -perm <id>:具有特定权限的文件

  • -user <user>:根据文件属主查找文件

  • -amin <n>:查找系统中最后 n 分钟访问的文件

  • -cmin <n>:查找系统中最后 n 分钟被改变文件状态的文件

  • -mmin <n>:查找系统中最后 n 分钟被改变文件数据的文件(对于上述三个命令,如果前面是 -,限制的是距当前一定时间内;而如果换用 +,限制的是距当前一定时间前。

  • -empty:空文件

  • -exec <command> { } \;:对 find 所匹配的文件执行该参数所给出的命令。如将 exec 换为 ok,则是以一种更安全的模式执行命令,在执行每个命令之前提示用户询问是否执行。

使用示例可参见 Linux 常用命令学习 | 菜鸟教程 (runoob.com) 之 17。

locate

locate 命令通过搜寻系统内建文档数据库查找符合条件的文档

用法:locate <参数> <范本样式...>

常用参数:

  • -r <reg>:使用正则表达式匹配
  • -l <num>:限定输出的条目数
  • -c:只输出找到的数量
  • -q:不显示错误输出
  • -i:忽略大小写

实战:文件目录查找

  1. 使用 find 统计文件系统中以 py 为后缀名的文件个数
  2. 使用 find 寻找 /home/ 文件夹下文件内容包含 datawhale 的文件
  3. 使用 locate 寻找到 python3.6.1.gz 文件

实操:

  1. 统计文件个数
1
2
3
4
5
6
7
## 这个为什么一定要用 find 呢,locate -c 不是更简单
[I have no name!@i-ym8u2kyp ~]$ find / -name "*.py" | wc -l # 使用 wc 对输出的换行符数进行统计,即可获知文件数量
find: ‘/proc/tty/driver’: Permission denied
find: ‘/proc/1/task/1/fd’: Permission denied
### 省略其他无权限报错
find: ‘/boot/grub2’: Permission denied
5907
  1. 发现包含特定内容的文件
1
2
3
4
5
6
7
8
9
10
# 仅用 find 并不能根据文件内容发现文件,需要结合 grep 使用
[I have no name!@i-ym8u2kyp ~]$ find /home -type f -exec grep -l "datawhale" {} \;
/home/datawhale/.bash_history
/home/datawhale/jane/affairs.pyc
/home/datawhale/gjb/__pycache__/affairs.cpython-36.pyc
### 符合条件文件过多,省略部分输出
/home/datawhale/geyashi.tar
/home/datawhale/chen.tar
/home/datawhale/zyc.zip
[I have no name!@i-ym8u2kyp ~]$
  1. 找到特定文件
1
2
[I have no name!@i-ym8u2kyp ~]$ locate python3.6.1.gz
/usr/share/man/man1/python3.6.1.gz