由于压缩解压、网络文件传输和定时任务都是实践中很常见的操作,这里进行更详细的命令介绍。

命令速查

解压缩并解包

1
2
3
tar --gzip -xf archive.tar.gz
tar --bzip2 -xf archive.tar.bz2
tar --xz -xf archive.tar.xz

解压缩并解包到指定位置

1
2
3
tar --gzip -xf archive.tar.gz -C /path/to/destination
tar --bzip2 -xf archive.tar.bz2 -C /path/to/destination
tar --xz -xf archive.tar.xz -C /path/to/destination

后缀.tgz视作.tar.gz

打包并压缩

1
2
3
tar --gzip -cf archive.tar.gz file1 file2 directory
tar --bzip2 -cf archive.tar.bz2 file1 file2 directory
tar --xz -cf archive.tar.xz file1 file2 directory

压缩解压

zip

zipunzip命令用于创建和解压缩.zip格式的压缩文件。

压缩文件的基本使用如下:创建一个名为 archive.zip 的压缩文件,并包含了指定的文件。

1
zip archive.zip file1 file2

需要注意的是,如果直接添加目录,那么只是添加了文件夹自身,不含其中的项!必须使用-r选项才能递归压缩整个目录

1
zip -r archive.zip directory

混合添加文件和文件夹也需要使用-r选项

1
zip -r archive.zip file1 file2 directory

解压缩文件的基本使用如下:解压缩名为 archive.zip 的压缩文件,并在当前位置恢复原始文件或目录结构。

1
unzip archive.zip

也可以指定解压后存放的目标位置/tmp(如果路径不存在,可能会尝试自动创建)

1
unzip archive.zip -d /tmp

查看压缩文件的内容(不会执行解压操作)

1
unzip -l archive.zip

gzip

gzip命令是Linux最基础的压缩命令,处理逻辑非常简单:

  • 只能压缩或解压单个文件,不支持多个文件或文件夹的处理
  • 不支持指定输出文件的名称,压缩后的输出文件名称就是在原始名称后面加上.gz,解压后的输出文件名称就是原始名称移除.gz
  • 解压只支持处理后缀为.gz的文件,其它后缀会报错;压缩同样不支持对后缀为.gz的文件进行,不会出现.gz.gz的情况
  • 无论是压缩还是解压的操作,默认都会将输入文件自动删除!或者理解为将其原位替换为输出文件(可以通过选项阻止自动删除)

压缩单个文件得到.gz文件

1
2
3
gzip a.txt
# [add] a.txt.gz
# [remove] a.txt

解压单个.gz文件(既可以使用-d选项,也可以使用专门的gunzip,两者等效)

1
2
3
4
5
gzip -d a.txt.gz
# [add] a.txt
# [remove] a.txt.gz

# or gunzip a.txt.gz

使用-k选项可以抑制对输入文件的自动删除,而是会将其保留

1
2
gzip -k a.txt
# [add] a.txt.gz

gzip只能对单个文件操作,如果传入多个文件,会将其中的每一项分别进行压缩或解压,例如

1
2
3
gzip file1 file2
# [add] file1.gz file2.gz
# [remove] file1 file2

也支持使用通配符,例如将当前目录下的所有文件压缩(并自动替换为压缩文件)

1
gzip *

gzip不支持对文件夹的压缩,如果直接传入文件夹名称会被忽略,例如

1
gzip folder/

这个命令是无效的,会被忽略并警告:folder是目录。但是我们可以加上-r选项,此时的处理逻辑是: 递归查找folder/及其子目录中的所有文件,分别将其压缩并替换掉原本的文件(仍然位于相应的子目录中)。

除此之外,还有如下的选项:

  • -v选项可以显示命令执行的细节
  • -l选项可以查看.gz文件的压缩率(不会执行解压)
  • -q选项可以静默执行

归档

tar命令严格来说不属于压缩解压命令,应该被称为打包命令或归档命令,本身不含执行任何的压缩算法,但是实践中通常会通过选项搭配压缩命令来使用,因此也放在这里讨论。

支持的基本选项如下:

  • -c, --create打包得到一个新归档
  • -x, --extract, --get从归档中解包
  • -f, --file=ARCHIVE指定将要处理归档文件名-f参数通常是必选的,后面必须立刻加上文件名参数)
  • -C, --directory=DIR:解包后展开到指定目录(缺省时会展开到当前目录)
  • -v, --verbose:显示指令执行过程中的信息
  • -t, --list:列出归档文件中的内容(不会将其解包)

打包解包

打包文件/目录为归档文件:

1
tar -cvf archive.tar file1 file2 directory

这将创建archive.tar文件,其中包含了指定的文件和目录。

解包归档文件到指定位置(默认的目标路径为当前位置)

1
2
tar -xvf archive.tar
tar -xvf archive.tar -C /path/to/destination

这将解包archive.tar文件,在目的地中恢复原始文件或目录结构:

  • 如果打包的是当前位置的一个文件夹folder/,那么解包后就会在目标路径创建文件夹./folder/
  • 如果打包的是当前位置的几个文件file1,file2,那么解包后就会在目标路径放置文件file1,file2
  • 如果打包时采用相对路径例如../file1,会移除../,解包之后仍然会把文件或文件夹放置在目标路径
  • 如果打包时采用绝对路径例如/path/to/file,会移除顶层/,解包后会在目标路径下创建path/to/file

查看归档信息

使用-tvf选项可以查看归档文件内容,但是不会将其展开

1
tar -tvf archive.tar

这将显示归档文件 archive.tar 中包含的文件和目录信息,例如

1
2
3
4
5
6
7
8
drwxrwxr-x ubuntu/ubuntu     0 2024-05-16 23:48 folder/
-rw-rw-r-- ubuntu/ubuntu 18 2024-05-16 23:47 folder/file1.txt
-rw-rw-r-- ubuntu/ubuntu 18 2024-05-16 23:47 folder/file-11.txt
-rw-rw-r-- ubuntu/ubuntu 18 2024-05-16 23:47 folder/file-12.txt
drwxrwxr-x ubuntu/ubuntu 0 2024-05-16 23:48 folder/subfolder/
-rw-rw-r-- ubuntu/ubuntu 18 2024-05-16 23:48 folder/subfolder/file-21.txt
-rw-rw-r-- ubuntu/ubuntu 18 2024-05-16 23:48 folder/subfolder/file-22.txt
-rw-rw-r-- ubuntu/ubuntu 18 2024-05-16 23:47 folder/file-13.txt

如果把-v移除,使用tar -tf则只会显示名称,不会显示完整列表,例如

1
2
3
4
5
6
7
8
folder/
folder/file1.txt
folder/file-11.txt
folder/file-12.txt
folder/subfolder/
folder/subfolder/file-21.txt
folder/subfolder/file-22.txt
folder/file-13.txt

这里显示的文件列表和目录结构就是解包之后会创建的所有内容,因此在解压之前有必要先查看一下,确保不会出现生成一大堆文件污染当前目录的问题。

附带压缩解压

可以使用特殊选项在打包解包的同时自动调用对应的压缩和解压命令:

  • -z-gzip:使用gzip,对应后缀为.tar.gz.tgz
  • -j-bzip2:使用bzip2,对应后缀为.tar.bz2
  • -J-xz:使用xz,对应后缀为.tar.xz

三种压缩命令略有区别:gzip最基础,通用性最强,压缩速度最快;xz压缩效率最高,对应的压缩速度最慢;bzip2大概介于两者之间。

先打包,然后使用某个压缩命令进行压缩

1
2
3
tar -zcvf archive.tar.gz file1 file2 directory
tar -jcvf archive.tar.bz2 file1 file2 directory
tar -Jcvf archive.tar.xz file1 file2 directory

使用某个压缩命令进行解压缩,然后解包

1
2
3
4
5
6
7
tar -zxvf archive.tar.gz
tar -jxvf archive.tar.bz2
tar -Jxvf archive.tar.xz

tar -zxvf archive.tar.gz -C /path/to/destination
tar -jxvf archive.tar.bz2 -C /path/to/destination
tar -Jxvf archive.tar.xz -C /path/to/destination

补充

tar命令实际上支持三种风格的调用方式,在不同的教程中可能使用了不同的方式,例如

1
2
3
4
5
6
7
8
# traditional style
tar cvf archive.tar file1.txt file2.txt

# UNIX style or short-option style
tar -cvf archive.tar file1.txt file2.txt

# GNU style or long-option style
tar --create --verbose --file=archive.tar file1.txt file2.txt

可以混用不同风格的调用方式,例如记不住不同的压缩包后缀对应的压缩解压命令,可以使用便于记忆的长选项来指定:

  • --gzip代表-g选项,对应后缀为.tar.gz
  • --bzip2代表-j选项,对应后缀为.tar.bz2
  • --xz代表-J选项,对应后缀为.tar.xz

然后只需要记住通用部分:

  • -xf代表解压并解包
  • -cf代表压缩并打包

这里可以加上v可以显示更详细的信息,如果包太大这些信息可能会很乱。

1
2
3
tar --gzip -xf archive.tar.gz
tar --bzip2 -xf archive.tar.bz2
tar --xz -xf archive.tar.xz

网络文件传输

wget

wget命令可以通过[url]下载对应的网络文件。最基本的用法如下

1
2
3
wget [url]

wget https://download.redis.io/releases/redis-6.0.8.tar.gz

加上-c选项支持断点续传,在下载之前会检查本地是否有未完成的下载,可以继续之前因为网络问题中断的大文件下载。

默认情况下,会使用[url]最后一个斜杠后的内容作为保存的文件名,可以使用-O选项指定下载到本地后保存的文件名

1
2
3
wget -O [filename] [url]

wget -O redis.tar.gz https://download.redis.io/releases/redis-6.0.8.tar.gz

如果原始文件名已经存在,默认情况下会在后面加后缀,不会自动覆盖,但是使用-O明确保存文件名时,会覆盖同名文件。

默认情况下,下载的文件会保存在当前工作目录中,可以使用-P选项将文件保存到指定目录下

1
2
3
wget -P [path] [url]

wget -P /usr/software https://download.redis.io/releases/redis-6.0.8.tar.gz

使用-i选项可以从多个[url]下载多个文件,需要我们把多个目标[url]保存在一个文本文件中,通过-i选项提供给wget

1
wget -i filelist.txt

文本文件例如

1
2
3
https://example.com/file1.zip
https://example.com/file2.zip
https://example.com/file3.zip

scp

scp是基于ssh的文件传输命令(需要保证可以通过ssh正常访问到远程服务器),包括下载和上传文件。最基本的上传和下载命令如下

1
2
3
4
5
# upload
scp [localfile] [user]@[hostname]:[remotedir]

# download
scp [user]@[hostname]:[remotefile] [localdir]

例如

1
2
scp /path/to/local/file user@remote_host:/path/to/remote/dir`
scp user@remote_host:/path/to/remote/file /path/to/local/dir`

对于远程路径,如果使用/开头则是绝对路径,否则基于用户家目录的相对路径,例如user@remote_host:path/to/remote/dir

还支持很多选项,例如:

  • -r:递归执行文件夹的所有文件(打包为压缩包的传输效率更高)
  • -P:指定端口
  • -v:输出详细内容
  • -i:指定ssh连接所使用的私钥文件

除了在本地和服务器之间,scp还支持两个远程服务器之间的文件传输,只要它们都可以通过ssh登陆即可

1
scp [user1]@[hostname1]:[remotefile1] [user2]@[hostname2]:[remotefile2]

curl

curl命令可以通过命令行模拟浏览器的各种网络请求,包括下载和上传文件,功能非常强大,但是返回的结果默认为标准输出流,下面提供几个常见示例。

-o--output: 将内容保存到指定文件中。

1
curl -o output.html http://example.com

-O--remote-name: 将下载的文件命名为远程文件名。

1
curl -O http://example.com/file.zip

-L--location: 跟随网络请求的重定向。

1
curl -L http://example.com

-u--user: 提供基本认证所需的用户名和密码。

1
curl -u username:password http://example.com

-s--silent: 静默模式,不输出进度或错误信息。

1
curl -s http://example.com

举一个例子,ustc的网络通可以通过下面的curl命令来开启

1
2
3
#!/bin/bash
curl --data "name=<username>&password=<password>&cmd=set&type=9&exp=0" \
http://wlt.ustc.edu.cn/cgi-bin/ip

但是这种简单实现不够安全,可以改为下面的做法,将敏感信息加密

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash

ERNAME="<username>"
PASSWORD="<password>"

CMD="set"
TYPE="9" # 出口
EXP="3600" # 时间1小时

URL="http://wlt.ustc.edu.cn/cgi-bin/ip"

curl --data-urlencode "name=${USERNAME}" \
--data-urlencode "password=${PASSWORD}" \
--data-urlencode "cmd=${CMD}" \
--data-urlencode "type=${TYPE}" \
--data-urlencode "exp=${EXP}" \
"${URL}"

一个等价的pwsh脚本如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$USERNAME = "<username>"
$PASSWORD = "<password>"

$CMD = "set"
$TYPE = "9" # 出口
$EXP = "3600" # 时间无限

$URL = "http://wlt.ustc.edu.cn/cgi-bin/ip"

curl --data-urlencode "name=$USERNAME" `
--data-urlencode "password=$PASSWORD" `
--data-urlencode "cmd=$CMD" `
--data-urlencode "type=$TYPE" `
--data-urlencode "exp=$EXP" `
$URL

这里的做法其实还是不够安全,因为账号和密码都被硬编码在脚本中。这些登陆脚本可以完全替代使用浏览器的过程,具体细节参考LUG的网络通脚本介绍

定时任务

在Linux系统中,crontab是一个非常强大的工具,可以用于在服务器中执行定时任务。

crontab 命令

查看当前用户的crontab任务列表

1
crontab -l

删除当前用户所有的crontab任务

1
crontab -r

编辑当前用户的crontab文件(使用vim打开)

1
crontab -e

crontab 语法

crontab文件中的每一行对应一个定时任务,其格式如下

1
2
3
4
5
6
7
8
* * * * * command
- - - - -
| | | | |
| | | | +---- 星期几 (0 - 7) (Sunday is both 0 and 7)
| | | +------ 月份 (1 - 12)
| | +-------- 每月的第几天 (1 - 31)
| +---------- 小时 (0 - 23)
+------------ 分钟 (0 - 59)

关于时间频率的语法,例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 每分钟执行一次
* * * * * /path/to/your/command

# 每天凌晨2:30执行一次
30 2 * * * /path/to/your/command

# 每周一凌晨3:00执行一次
0 3 * * 1 /path/to/your/command

# 每周一到周五的每小时执行一次
0 * * * 1-5 /path/to/your/command

# 每月1号凌晨4:00执行一次
0 4 1 * * /path/to/your/command

对于执行的命令,需要特别注意:crontab中的命令被执行时,默认不会加载用户的环境变量,尽量使用绝对路径,或者在脚本中设置所需的环境变量。

为了调试和记录任务执行情况,可以将输出重定向到日志文件,例如

1
* * * * * /path/to/your/command >> /path/to/logfile 2>&1