HiSEN

Shell 批量解压文件并重命名 - 解决文件名冲突

一、背景

由于某种原因,需要手工处理错误日志提取某些信息。
下载下来的日志文件是压缩包

1.1 文件信息

1
2
3
4
system_error.log.2020-11-01.20201105200433.zip
system_error.log.2020-11-01.20201105195953.zip
system_error.log.2020-11-01.20201105200830.zip
...省略

1.2 压缩包信息

1
2
3
4
5
6
7
$ unzip -v system_error.log.2020-11-01.20201105200830.zip
Archive: system_error.log.2020-11-01.20201105200830.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
4495560 Defl:N 78526 98% 11-01-2020 23:43 504551c6 system_error.log.2020-11-01
-------- ------- --- -------
4495560 78526 98% 1 file

压缩包文件名不一样,但是压缩包中的文件有一样的名字。
例如:system_error.log.2020-11-01

尝试使用如下方式,提示有重复,需要挨个选择如何处理,极度不便。
于是想使用 shell 来解决( 之前没写过 shell )

1.2 尝试过程

提示有文件重复,需要处理。

1
2
3
$ unzip '*.zip'
Archive: system_error.log.2020-10-15.20201105200943.zip
replace system_error.log.2020-10-15? [y]es, [n]o, [A]ll, [N]one, [r]ename:

尝试使用 -n 参数,不覆盖

1
2
3
4
$ unzip -n '*.zip'
Archive: system_error.log.2020-10-15.20201105200943.zip
...省略
100 archives were successfully processed.

-n 表示不覆盖,有重名的直接跳过,结果就是 100 个文件只解压的 10 个。

1.3 怎么解压并且重命名?

1
2
mv A B
# 把 A 改名为 B

怎么拿到压缩包内的文件名?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 输出压缩包内的信息
$ unzip -v system_error.log.2020-11-01.20201105200830.zip
Archive: system_error.log.2020-11-01.20201105200830.zip
Length Method Size Cmpr Date Time CRC-32 Name
-------- ------ ------- ---- ---------- ----- -------- ----
4495560 Defl:N 78526 98% 11-01-2020 23:43 504551c6 system_error.log.2020-11-01
-------- ------- --- -------
4495560 78526 98% 1 file

# 使用 awk 截取相关信息
# NR 行号,NF 最后一列
# unzip -v 的输出方式可能有变动,需要自己修改位置,以得到正确的结果
$ unzip -v system_error.log.2020-11-01.20201105200830.zip | awk '{if(NR==4) print $NF}'
system_error.log.2020-11-01

二、脚本信息

1.3 的问题解决了就可以开始写脚本

2.1 脚本

文件名 uf.sh

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#!/bin/sh
# 压缩包目录
srcDir=$1
# 解压后文件存放目录
dstDir=$2
# 文件名序号
seq=1
for file in ${srcDir}/*
do
# 判断是否为文件
if test -f $file
then
# 获取压缩包名称,例如:system_error.log.2020-11-01.20201105200830.zip
filename=$(basename $file)
# 解压文件,移动文件,并且改名(这里使用的是序号,可以截取原文件名拼接时间戳等避免重名)
unzip $filename && mv `unzip -v $filename | awk '{if(NR==4){print $8}}'` ${dstDir}/$((seq++))
fi
done

2.2 使用方法

注意,目前在目标目录下才能正确运行

1
2
chmod 775 uf.sh
sh uf.sh ./src ./dst

然后解决问题,解压所有 100 个压缩包,并且得到 100 个文件(文件名为 1~100)。

三、总结

不得不说解决问题是最快的学习方式
第一次写脚本相对耗时,也是一个不错的尝试过程。
对linux系统相关的命令/函数不熟悉,导致到处查资料,有必要系统化的看看书。

四、参考信息