
linux下自定义tartree脚本工具展示压缩包树形结构
背景
在 linux 环境下,需要经常下载源码包、部署包之类的压缩包,一般是 tar、tar.gz 压缩包,大部分下载到的压缩包里面会有一层根目录,但免不了有一些压缩包里面没有一个根目录,而是直接就是各种文件
在 windows 系统的时候,我都会先打开压缩包看看里面的目录结构,再决定需不需要新建一个文件夹来存放,但在 linux 系统中,暂时还没找到可以按层级展示压缩包里面目录结构的工具,而 tar -tf 这种命令输出的都是文件的全路径,不直观
所以啊,自己写了个 shell 脚本,在不真正解压的情况下,将压缩包里面的文件目录按树形结构打印出来
脚本
功能
脚本支持 tar、tar.gz、tar.bz2、tar.lzma、tar.lz、tar.zst、zip、7z、rar 这几种压缩包,其中,zip、rar 这两种压缩包,需要自己先安装 unzip、unrar 这两个工具
unzip:apt、yum 可以安装
unrar:需要从官网下载安装
wget https://www.rarlab.com/rar/rarlinux-x64-6.0.2.tar.gz
tar -zxf rarlinux-x64-6.0.2.tar.gz
cd rar
sudo make
使用步骤
在 /usr/local/bin 下面新建一个文件 tartree
给 tartree 可执行权限,sudo chmod +x /usr/local/bin/tartree
将文章后面的脚本内容粘贴到 tartree.sh 就能愉快的使用了
用法
用法: tartree [选项] -f <压缩包路径>
示例:
查看tar包的目录结构:tartree -f ./test.tar
查看tar.gz包的目录结构:tartree -z -f./test.tar.gz
查看zip包的目录结构:tartree --zip -f./test.zip
选项:
-z 处理 tar.gz 格式的压缩包
-j 处理 tar.bz2 格式的压缩包
-J 处理 tar.xz 格式的压缩包
--tar 处理 tar 格式的压缩包,这也是默认的压缩类型
--lzma 处理 tar.lzma 格式的压缩包
--lzip 处理 tar.lz 格式的压缩包
--zstd 处理 tar.zst 格式的压缩包
--zip 处理 zip 格式的压缩包
--7z 处理 7z 格式的压缩包
--rar 处理 rar 格式的压缩包
--depth <n> 显示的最大层级,n 为正整数
-h, --help 显示此帮助信息
脚本代码
#!/bin/bash
# 作者:kk
# 初始化变量
compression_type="tar"
tar_file=""
max_depth=0
# 定义帮助信息
help_info="
用法: $0 [选项] -f <压缩包路径>
示例:
查看tar包的目录结构:$0 -f ./test.tar
查看tar.gz包的目录结构:$0 -z -f./test.tar.gz
查看zip包的目录结构:$0 --zip -f./test.zip
选项:
-z 处理 tar.gz 格式的压缩包
-j 处理 tar.bz2 格式的压缩包
-J 处理 tar.xz 格式的压缩包
--tar 处理 tar 格式的压缩包,这也是默认的压缩类型
--lzma 处理 tar.lzma 格式的压缩包
--lzip 处理 tar.lz 格式的压缩包
--zstd 处理 tar.zst 格式的压缩包
--zip 处理 zip 格式的压缩包
--7z 处理 7z 格式的压缩包
--rar 处理 rar 格式的压缩包
--depth <n> 显示的最大层级,n 为正整数
-h, --help 显示此帮助信息
"
# 解析命令行参数
while [[ $# -gt 0 ]]; do
case "$1" in
-h|--help)
echo "$help_info"
exit 0
;;
-z)
compression_type="gz"
shift
;;
-j)
compression_type="bz2"
shift
;;
-J)
compression_type="xz"
shift
;;
--tar)
compression_type="tar"
shift
;;
--lzma)
compression_type="lzma"
shift
;;
--lzip)
compression_type="lz"
shift
;;
--zstd)
compression_type="zst"
shift
;;
--zip)
if [ -z "`command -v unzip`" ]; then
echo "错误: 未安装 unzip 工具。"
exit 250
fi
compression_type="zip"
shift
;;
--7z)
if [ -z "`command -v 7z`" ]; then
echo "错误: 未安装 7z 工具。"
exit 250
fi
compression_type="7z"
shift
;;
--rar)
if [ -z "`command -v unrar`" ]; then
echo "错误: 未安装 unrar 工具。"
exit 250
fi
compression_type="rar"
shift
;;
-f)
if [[ -n "$2" ]]; then
tar_file="$2"
shift 2
else
echo "错误: -f 参数后需要跟压缩包路径。"
exit 1
fi
;;
--depth)
if [[ -n "$2" && "$2" =~ ^[1-9][0-9]*$ ]]; then
max_depth="$2"
shift 2
else
echo "错误: --depth 参数后需要跟一个正整数。"
exit 1
fi
;;
*)
echo "错误: 未知参数 $1。"
exit 1
;;
esac
done
# 检查 -f 参数是否提供了压缩包路径
if [[ -z "$tar_file" ]]; then
echo "错误: 必须提供 -f 参数指定压缩包路径。"
exit 1
fi
# 检查压缩包是否存在
if [ ! -f "$tar_file" ]; then
echo "错误: 指定的压缩包 $tar_file 不存在。"
exit 1
fi
# 根据压缩类型选择合适的命令
case "$compression_type" in
tar)
command="tar -tf"
;;
gz)
command="tar -ztf"
;;
bz2)
command="tar -jtf"
;;
xz)
command="tar -Jtf"
;;
lzma)
command="tar --lzma -tf"
;;
lz)
command="tar --lzip -tf"
;;
zst)
command="tar --zstd -tf"
;;
zip)
command="unzip -l"
;;
7z)
command="7z l"
;;
rar)
command="unrar l"
;;
*)
echo "错误: 不支持的压缩类型。"
exit 1
;;
esac
current_row=0
_zip_7z_rar_status=0
# 定义一个map存放出现过的前缀
declare -A prefix_map
$command "$tar_file" | while IFS= read -r line; do
((current_row++))
# zip, 7z, rar 特殊处理
if [[ "$compression_type" =~ ^(zip|7z|rar)$ ]]; then
# zip, 7z, rar 真正有用的是 ------ ... ------ 包裹着的内容,所以要去掉前面几行和后面几行
if [[ $_zip_7z_rar_status -eq 0 ]]; then
if [[ "${line:0:6}" == "------" ]]; then
_zip_7z_rar_status=1
fi
continue
fi
if [[ $_zip_7z_rar_status -eq 1 ]]; then
if [[ "${line:0:6}" == "------" ]]; then
exit 0
fi
fi
# 针对 zip、7z、rar 输出格式,提取文件名部分
if [[ "$compression_type" == "zip" ]]; then
line=${line:30}
elif [[ "$compression_type" == "7z" ]]; then
line=${line:53}
elif [[ "$compression_type" == "rar" ]]; then
line=${line:41}
fi
fi
# 如果这一行里没有 / ,则手动加上,避免下面逻辑无法按 / 切割字符串
if [[ $line != *"/"* ]]; then
line="/${line}"
fi
# 如果最后一个字符是 /,则手动再拼接上一个空格,避免下面逻辑无法按 / 切割字符串
if [[ "${line: -1}" == "/" ]]; then
line="${line} "
fi
# 按 / 切割字符串
IFS='/' read -r -a parts <<< "$line"
current_prefix=""
indent="|"
current_depth=0
part_index=-1
for part in "${parts[@]}"; do
((part_index++))
# 是否是最后一个元素
is_last_part=$((part_index == ${#parts[@]} - 1))
# 去掉前后空白符号
part="${part#"${part%%[![:space:]]*}"}"
part="${part%"${part##*[![:space:]]}"}"
# 只有不是空字符串才处理
if [[ -n $part ]]; then
# 当前深度加 1
((current_depth++))
if [ $max_depth -gt 0 ] && [ $current_depth -gt $max_depth ]; then
continue
fi
# 拼接出当前前缀
current_prefix="${current_prefix}/${part}"
tmp_value=${prefix_map[$current_prefix]}
# 前缀没出现过,则将当前层级打印出来
if [[ "$tmp_value" = "" ]]; then
tmp_echo_part="${part}"
# 如果当前并不是最后一层,那这一层肯定是目录,则输出的时候加上 /
if [[ ! $is_last_part -eq 1 ]]; then
tmp_echo_part="${tmp_echo_part}/"
fi
echo "${indent}--${tmp_echo_part}"
# 标记一下当前层级出现过了
prefix_map[$current_prefix]="1"
fi
# 增加一层缩进
indent="${indent} |"
fi
done
done
本文是原创文章,采用 CC 4.0 BY-SA 协议,完整转载请注明来自 KK元空间
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果