在 Linux 上,有一些常用的工具来支持 zip
、unzip
和 zipmerge
。你可以按照以下步骤来安装这些工具:
1. 使用包管理器更新软件包缓存。
具体命令取决于你所使用的 Linux 发行版,请根据以下示例选择其中之一:
- 对于 Debian 或 Ubuntu:
sudo apt update -y
- 对于 CentOS 或 Fedora:
sudo yum update -y
- 对于 Arch Linux:
sudo pacman -Sy
安装 zip
和 unzip
工具:
- 对于 Debian 或 Ubuntu:
sudo apt install -y zip unzip
- 对于 CentOS 或 Fedora:
sudo yum install -y zip unzip
- 对于 Arch Linux:
sudo pacman -S zip unzip
安装 zipmerge
工具:
- 在 Debian 或 Ubuntu 上使用
zipmerge
:
sudo apt install -y zipmerge
- 在 CentOS 或 Fedora 上,
zipmerge
命令在unzip
软件包中提供:
sudo yum install -y unzip
- 在 Arch Linux 上,
zipmerge
命令在zip
软件包中提供:
sudo pacman -S zip
安装完成后,你就可以使用 zip
、unzip
和 zipmerge
命令来管理和合并 zip 文件。
请注意,这些命令需要以
root
或具有sudo
访问权限的账户运行。如果你没有适当的权限,请联系系统管理员进行安装。
特殊情况
安装 perl-Archive-Zip
在 CentOS 7 上,默认安装的 unzip
软件包中不包含 zipmerge
命令。要使用 zipmerge
命令,你可以按照以下步骤安装 zipmerge
:
- 首先,安装 epel-release 仓库。在 CentOS 7 上,epel-release 是一个附加软件包库,其中包含了许多其他软件包。
sudo yum install epel-release
- 安装
zipmerge
:
sudo yum install perl-Archive-Zip
- 安装完成后,你应该能够使用
zipmerge
命令了。请注意,zipmerge
命令的安装和使用可能因不同的 Linux 发行版而有所不同。
如果你仍然无法使用 zipmerge
命令,请确保你已经成功安装了 epel-release 仓库,并尝试重新安装 perl-Archive-Zip
软件包。有时候会出现 perl-Archive-Zip
软件包中的 zipmerge
命令被禁用或删除的情况。在这种情况下,你可以手动安装 zipmerge
脚本。如果问题仍然存在,你可以查找其他替代的 zip
文件合并工具来完成任务。
手动安装 zipmerge
脚本
请按照以下步骤操作:
- 创建一个新目录来存放
zipmerge
脚本:
sudo mkdir /opt/zipmerge
- 下载
zipmerge
脚本并将其移动到新创建的目录中:
sudo curl -o /opt/zipmerge/zipmerge https://raw.githubusercontent.com/gregoryszorc/zipmerge/master/zipmerge
- 给予
zipmerge
脚本执行权限:
sudo chmod +x /opt/zipmerge/zipmerge
- 现在,你可以使用下面的命令来运行
zipmerge
:
# 直接通过全路径使用
/opt/zipmerge/zipmerge output.zip input1.zip input2.zip ...
# 添加软链接:ln -s <目标文件或目录> <链接文件路径>
sudo ln -s /opt/zipmerge/zipmerge /usr/bin/zipmerge
# 使用示例
zipmerge output.zip input1.zip input2.zip ...
请注意,这种方法使用的是来自 zipmerge
项目的 zipmerge
脚本,并不是由 CentOS 官方提供的软件包。因此,使用之前请了解其中可能的风险和限制。
如果你仍然无法使用 zipmerge
命令,可能需要考虑使用其他的 zip
合并工具来完成任务。
通过 unzip、cat、zip 命令组合
如果以上方案均无法实现 zipmerge
功能,可通过创建一个名为 zipmerge
的脚本,通过组合使用 unzip
、cat
和 zip
命令来实现 zipmerge
的功能。如果待合并的 zip
文件有规律,你可以使用正则表达式来匹配文件名,并将匹配的文件作为参数传递给 zipmerge
函数。以下是一个支持通过正则表达式来匹配待合并的 zip
文件的函数实现:
注意事项:
以下脚本选项不能连写,如-cD
是不支持的,需要分开写,如-c
-D
,这也是相较getopt
实现上较不灵活的地方。
该脚本只是提供一种实现思路,实现上超级简单粗暴,将占用大量的硬盘空间,慎用。
#!/bin/bash
#### 使用示例 ####
# 此处以本脚本保存为 /usr/bin/zipmerge 为例
# 合并两个 zip 文件为一个目标 .zip 文件
# 并将同名文件合并为一个文件
# 打印合并详细信息
# 使用方法: zipmerge -v -c 目标.zip file1.zip file2.zip
# 合并三个 zip 文件为一个目标 .zip 文件
# 不合并同名文件
# 不打印合并详细信息
# 使用方法: zipmerge 目标.zip file1.zip file2.zip file3.zip
usage() {
echo "使用方法: $0 [选项] 目标.zip [zip文件(支持正则匹配)...]"
echo "选项:"
echo " -h, --help 打印帮助信息"
echo " -v 打印合并详细信息"
echo " -c 合并同名文件为一个文件"
echo " -D 忽略文件中的目录(同名文件根据 -c 确认是否合并)"
}
merge_zip() {
local target_zip=$1
shift
# 创建临时目录
local temp_dir=$(mktemp -d)
local target_dir=$(mktemp -d)
local counter=1
# 解压缩并合并
for file in "$@"; do
unzip -q "$file" -d "$temp_dir/zip$counter"
counter=$((counter + 1))
done
# 合并同名文件
find "$temp_dir" -type f -print0 | while IFS= read -r -d '' file; do
# 文件名解析
filename=$(basename "$file")
if [ "$ignore_directory" != true ]; then
# 取临时目录后的相对路径
filename=$(echo "$file" | sed -E "s#^${temp_dir}/zip[0-9]*/##")
fi
echo "filename: $filename"
target_file="$target_dir/$filename"
if [ "$ignore_directory" != true ]; then
# 提取目录信息
directory=$(dirname "$target_file")
# 创建目录(如果不存在)
mkdir -p "$directory"
fi
if [ "$merge_same_named" = true ]; then
# 合并文件信息
echo "cat $file >> $target_file"
cat "$file" >> "$target_file"
else
# 重置重复文件计数
counter=1
# 对同名文件添加后缀
while [ -e "$target_file" ]; do
target_file="$target_dir/${filename%.*}($counter).${filename##*.}"
counter=$((counter + 1))
done
echo "cp $file $target_file"
cp "$file" "$target_file"
fi
done
# 压缩目标目录
local target_zip_dir=$PWD
cd $target_dir
zip -q -r "$target_zip_dir/$target_zip" ./
# 清理临时目录
rm -rf "$temp_dir"
rm -rf "$target_dir"
}
target_zip=""
zip_files=()
merge_same_named=false
print_details=false
# 解析命令行参数
while [[ $# -gt 0 ]]; do
case $1 in
-h|--help)
usage
exit 0
;;
-v)
print_details=true
shift
;;
-c)
merge_same_named=true
shift
;;
-D)
ignore_directory=true
shift
;;
*)
if [ -z "$target_zip" ]; then
target_zip="$1"
else
zip_files+=("$1")
fi
shift
;;
esac
done
# 检查是否提供了目标.zip文件
if [ -z "$target_zip" ]; then
echo "未指定目标 zip 文件"
usage
exit 1
fi
# 检查是否提供了 zip 文件
if [ ${#zip_files[@]} -eq 0 ]; then
echo "未指定待合并 zip 文件(至少需要一个)"
usage
exit 1
fi
# 合并zip文件
if [ "$print_details" = true ]; then
echo "正在合并 zip 文件:"
for file in "${zip_files[@]}"; do
echo " - $file"
done
echo "目标 zip 文件: $target_zip"
echo "是否合并同名文件: $merge_same_named"
echo "打印合并详细信息..."
fi
merge_zip "$target_zip" "${zip_files[@]}"
echo "Zip 合并完成"
该脚本的工作原理如下:
usage
函数:打印帮助信息,显示脚本的使用方法和选项说明。merge_zip
函数:实际执行 zip 文件合并的主要逻辑。它接收目标 zip 文件和待合并的 zip 文件列表作为参数。在临时目录中解压待合并的 zip 文件,并在目标目录中保存合并的文件。如果使用了-c
选项,则将同名文件合并为一个文件,否则会对同名文件添加后缀来避免冲突。然后将目标目录的内容压缩为目标 zip 文件。- 解析命令行参数:使用
while
循环和case
语句解析命令行参数。可以使用-h
或--help
选项打印帮助信息。-v
选项用于启用打印详细信息的模式。-c
选项用于合并同名文件。-D
选线用于忽略文件中的目录(同名文件根据-c
确认是否合并)。剩余的参数中,第一个参数被认为是目标 zip 文件,其他参数被视为待合并的 zip 文件。 - 检查参数:检查是否提供了目标 zip 文件和待合并的 zip 文件。如果没有提供,将打印错误消息并显示帮助信息。
- 打印详细信息:如果启用了打印详细信息的模式,将打印待合并的 zip 文件列表、目标 zip 文件和是否合并同名文件的状态。
- 调用
merge_zip
函数:传递目标 zip 文件和待合并的 zip 文件列表作为参数,执行实际的 zip 合并操作。 - 最后,打印合并完成的消息。
这个脚本允许你通过指定目标 zip 文件和待合并的 zip 文件列表,以及选择是否合并同名文件来进行 zip 文件合并。你可以根据自己的需求将其保存到 /usr/bin/zipmerge
或其他位置,并使用 zipmerge
命令来执行 zip 文件合并操作。
为了方便使用,提供 getopt
参数解析实现版本:
注意事项:
以下脚本虽然实现了文件的合并,但是实现上比较简单粗暴,只是简单地将待合并的zip文件分别解压缩到独立的目录,然后根据指定的选项对解压缩后的文件进行处理。如果待合并的zip文件的压缩率较高,且文件较大,则将占用较大的硬盘空间,存在爆盘的风险。
#!/bin/bash
#### 使用示例 ####
# 此处以本脚本保存为 /usr/bin/zipmerge 为例
# 合并两个 zip 文件为一个目标 .zip 文件
# 并将同名文件合并为一个文件
# 打印合并详细信息
# 使用方法: zipmerge -v -c 目标.zip file1.zip file2.zip
# 合并三个 zip 文件为一个目标 .zip 文件
# 不合并同名文件
# 不打印合并详细信息
# 使用方法: zipmerge 目标.zip file1.zip file2.zip file3.zip
# 获取脚本开始的时间戳(毫秒)
start_time=$(date +%s%3N)
# 检查并安装命令
check_and_install_command() {
local command_name=$1
local package_name=$2
# 检查命令是否存在
if ! command -v $command_name &> /dev/null; then
echo "未找到 $command_name 命令,正在安装..."
# 检查操作系统类型
if [[ "$(uname)" == "Darwin" ]]; then
# macOS,使用 Homebrew 安装命令
brew install $package_name
elif [[ -x "$(command -v apt-get)" ]]; then
# Debian/Ubuntu,使用 apt 安装命令
sudo apt-get install $package_name -y
elif [[ -x "$(command -v yum)" ]]; then
# RHEL/CentOS,使用 yum 安装命令
sudo yum install $package_name -y
elif [[ -x "$(command -v dnf)" ]]; then
# Fedora,使用 dnf 安装命令
sudo dnf install $package_name -y
else
echo "无法自动安装 $command_name 命令,请手动安装。"
fi
else
echo "$command_name 命令已安装。"
fi
}
# 检查和安装 zip 命令
check_and_install_command "zip" "zip"
# 检查和安装 unzip 命令
check_and_install_command "unzip" "unzip"
usage() {
echo "使用方法: $0 [选项] 目标.zip [zip文件(支持正则匹配)...]"
echo "选项:"
echo " -h, --help 打印帮助信息"
echo " -v 打印合并详细信息"
echo " -c 合并同名文件为一个文件"
echo " -D 忽略文件中的目录(同名文件根据 -c 确认是否合并)"
}
target_zip=""
zip_files=()
merge_same_named=false
print_details=false
# 命令解析
options=$(getopt -o hvcD --long help -n "$(basename "$0")" -- "$@")
# 如果参数不合法,则打印使用说明并退出
if [ $? -ne 0 ]; then
usage; exit
fi
# 参数解析与处理
eval set -- "${options}"
while true; do
case "$1" in
-h|--help)
usage
exit 0
;;
-v)
print_details=true
shift
;;
-c)
merge_same_named=true
shift
;;
-D)
ignore_directory=true
shift
;;
--)
shift
break
;;
*)
echo "未知选项: $1"
usage
exit 1
;;
esac
done
# 获取目标.zip文件和待合并zip文件
target_zip=$1
shift
# 检查是否提供了目标.zip文件
if [ -z "$target_zip" ]; then
echo "未指定目标 zip 文件"
usage
exit 1
fi
# 检查是否提供了 zip 文件
if [ $# -eq 0 ]; then
echo "未指定待合并 zip 文件(至少需要一个)"
usage
exit 1
fi
# 合并zip文件
if [ "$print_details" = true ]; then
echo "正在合并 zip 文件:"
for file in "$@"; do
echo " - $file"
done
echo "目标 zip 文件: $target_zip"
echo "是否合并同名文件: $merge_same_named"
echo "打印合并详细信息..."
fi
merge_zip() {
local target_zip=$1
shift
# 创建临时目录
local temp_dir=$(mktemp -d)
local target_dir=$(mktemp -d)
local counter=1
#echo "temp_dir: $temp_dir"
#echo "target_dir: $target_dir"
zip_flags=""
# 根据选项判断是否输出详细信息
[ "$print_details" = true ] || zip_flags+="-q"
# 解压缩并合并
for file in "$@"; do
unzip $zip_flags "$file" -d "$temp_dir/zip$counter"
counter=$((counter + 1))
done
# 合并同名文件
find "$temp_dir" -type f -print0 | while IFS= read -r -d '' file; do
# 文件名解析
filename=$(basename "$file")
if [ "$ignore_directory" != true ]; then
# 取临时目录后的相对路径
filename=$(echo "$file" | sed -E "s#^${temp_dir}/zip[0-9]*/##")
fi
#echo "filename: $filename"
target_file="$target_dir/$filename"
if [ "$ignore_directory" != true ]; then
# 提取目录信息
directory=$(dirname "$target_file")
# 创建目录(如果不存在)
mkdir -p "$directory"
fi
if [ "$merge_same_named" = true ]; then
# 合并文件信息
#echo "cat $file >> $target_file"
cat "$file" >> "$target_file"
rm -f "$file"
else
# 重置重复文件计数
counter=1
# 对同名文件添加后缀
while [ -e "$target_file" ]; do
target_file="$target_dir/${filename%.*}($counter).${filename##*.}"
counter=$((counter + 1))
done
#echo "mv $file $target_file"
mv "$file" "$target_file"
fi
done
# 压缩目标目录
local target_zip_dir=$PWD
cd $target_dir
zip -r $zip_flags "$target_zip_dir/$target_zip" ./
# 清理临时目录
rm -rf "$temp_dir"
rm -rf "$target_dir"
}
merge_zip "$target_zip" "$@"
echo "Zip 合并完成"
# 获取脚本结束的时间戳(毫秒)
end_time=$(date +%s%3N)
# 计算脚本执行时间(毫秒级)
duration=$(echo "scale=3; ($end_time - $start_time) / 1000" | bc)
# 打印处理时间
echo "脚本执行时间为:$duration 秒"
TIPS: 可以通过
zipinfo
查看 zip 文件中的所有文件
zipinfo
是一个用于查看 zip 文件内容的命令行工具。它提供了有关 zip 文件中包含的文件的信息,如文件名、大小、压缩比率、日期和时间等。
使用 zipinfo
可以执行以下操作:
- 列出 zip 文件中的所有文件:
zipinfo archive.zip
- 查看特定文件的详细信息:
zipinfo archive.zip file.txt
- 以详细格式显示 zip 文件中的所有文件信息:
zipinfo -l archive.zip
zipinfo
支持多种选项,用于配置其输出形式和显示结果的详细程度。一些常用选项包括:
-v
:以详细模式显示文件信息;-s
:仅显示文件名;-t
:显示文件的压缩日期和时间;-z
:显示文件的压缩比率。
使用 zipinfo
可以方便地查看 zip 文件中的内容,了解其中的文件信息,以及对文件进行必要的检查和验证。
最终版
本脚本优化了峰值硬盘空间占用问题,但是整体效率相对上一个版本低。
#!/bin/bash
#### 使用示例 ####
# 此处以本脚本保存为 /usr/bin/zipmerge 为例
# 合并两个 zip 文件为一个目标 .zip 文件
# 并将同名文件合并为一个文件
# 打印合并详细信息
# 使用方法: zipmerge -v -c 目标.zip file1.zip file2.zip
# 合并三个 zip 文件为一个目标 .zip 文件
# 不合并同名文件
# 不打印合并详细信息
# 使用方法: zipmerge 目标.zip file1.zip file2.zip file3.zip
# 获取脚本开始的时间戳(毫秒)
start_time=$(date +%s%3N)
# 检查并安装命令
check_and_install_command() {
local command_name=$1
local package_name=$2
# 检查命令是否存在
if ! command -v $command_name &> /dev/null; then
echo "未找到 $command_name 命令,正在安装..."
# 检查操作系统类型
if [[ "$(uname)" == "Darwin" ]]; then
# macOS,使用 Homebrew 安装命令
brew install $package_name
elif [[ -x "$(command -v apt-get)" ]]; then
# Debian/Ubuntu,使用 apt 安装命令
sudo apt-get install $package_name -y
elif [[ -x "$(command -v yum)" ]]; then
# RHEL/CentOS,使用 yum 安装命令
sudo yum install $package_name -y
elif [[ -x "$(command -v dnf)" ]]; then
# Fedora,使用 dnf 安装命令
sudo dnf install $package_name -y
else
echo "无法自动安装 $command_name 命令,请手动安装。"
fi
fi
}
# 检查和安装 zip 命令
check_and_install_command "zip" "zip"
# 检查和安装 unzip 命令
check_and_install_command "unzip" "unzip"
# 检查和安装 bc 命令
check_and_install_command "bc" "bc"
usage() {
echo "使用方法: $0 [选项] 目标.zip [zip文件(支持正则匹配)...]"
echo "选项:"
echo " -h, --help 打印帮助信息"
echo " -v 打印合并详细信息"
echo " -c 合并同名文件为一个文件"
echo " -D 忽略文件中的目录(同名文件根据 -c 确认是否合并)"
echo " -p 性能模式,压缩率高的大文件合并请结合实际硬盘情况使用,有爆盘风险,性能提升 50%+,文件越多,提升越大。"
}
target_zip=""
zip_files=()
merge_same_named=false
print_details=false
# 命令解析
options=$(getopt -o hvcpD --long help -n "$(basename "$0")" -- "$@")
# 如果参数不合法,则打印使用说明并退出
if [ $? -ne 0 ]; then
usage; exit
fi
# 参数解析与处理
eval set -- "${options}"
while true; do
case "$1" in
-h|--help)
usage
exit 0
;;
-v)
print_details=true
shift
;;
-c)
merge_same_named=true
shift
;;
-p)
performance_mode=true
shift
;;
-D)
ignore_directory=true
shift
;;
--)
shift
break
;;
*)
echo "未知选项: $1"
usage
exit 1
;;
esac
done
# 获取目标 zip 文件
target_zip=$1
shift
# 检查是否提供了目标 zip 文件
if [ -z "$target_zip" ]; then
echo "未指定目标 zip 文件"
usage
exit 1
fi
# 检查是否提供了 zip 文件
if [ $# -eq 0 ]; then
echo "未指定待合并 zip 文件(至少需要一个)"
usage
exit 1
fi
# 合并 zip 文件
if [ "$print_details" = true ]; then
echo "正在合并 zip 文件:"
for file in "$@"; do
echo " - $file"
done
echo "目标 zip 文件: $target_zip"
echo "是否合并同名文件: $merge_same_named"
echo "打印合并详细信息..."
fi
# 将 target_zip 改写为绝对路径
if [[ $target_zip != /* ]]; then
target_zip="$(readlink -f $target_zip)"
fi
# 根据选项判断是否输出详细信息
zip_flags=""
[ "$print_details" = true ] || zip_flags+="-q"
# 添加文件到目标 zip 文件中
add_file_to_zip() {
local target_zip=$1
local unzip_dir=$2
local file=$3
# 获取文件名
filename=$(basename "$file")
if [ "$ignore_directory" != true ]; then
# 取临时目录后的相对路径
filename=$(echo "$file" | sed -E "s#^${unzip_dir}/##")
fi
# 判断是否需要合并同名文件
if [ "$merge_same_named" = true ]; then
# 检查目标 zip 文件中是否存在同名文件
if unzip -l "$target_zip" "$filename" >/dev/null 2>&1; then
# 解压目标 zip 文件中的文件到临时文件夹
temp_unzip_dir=$(mktemp -d)
unzip $zip_flags "$target_zip" "$filename" -d "$temp_unzip_dir"
target_file="$temp_unzip_dir/$filename"
if [ "$ignore_directory" != true ]; then
# 提取目录信息
directory=$(dirname "$target_file")
# 创建目录(如果不存在)
mkdir -p "$directory"
fi
# 合并文件
cat "$file" >> "$temp_unzip_dir/$filename"
# 将合并后的文件添加到目标 zip 文件中
cd $temp_unzip_dir
zip -r $zip_flags "$target_zip" $filename
# 清除临时文件夹
rm -rf "$temp_unzip_dir"
else
# 将文件直接添加到目标 zip 文件中
cd $unzip_dir
zip -r $zip_flags "$target_zip" "$filename"
fi
else
# 对同名文件添加后缀
counter=1
test_filename=$filename
while unzip -l "$target_zip" "$test_filename" >/dev/null 2>&1; do
test_filename="${filename%.*}($counter).${filename##*.}"
counter=$((counter + 1))
done
if [[ $counter -gt 1 ]]; then
mv $file $unzip_dir/$test_filename
fi
cd $unzip_dir
zip -r $zip_flags "$target_zip" "$test_filename"
fi
}
merge_zip() {
local target_zip=$1
shift
# 创建临时目录
local temp_dir=$(mktemp -d)
local target_dir=$(mktemp -d)
local counter=1
zip_flags=""
# 根据选项判断是否输出详细信息
[ "$print_details" = true ] || zip_flags+="-q"
# 解压缩并合并
for file in "$@"; do
unzip $zip_flags "$file" -d "$temp_dir/zip$counter"
counter=$((counter + 1))
done
# 合并同名文件
find "$temp_dir" -type f -print0 | while IFS= read -r -d '' file; do
# 文件名解析
filename=$(basename "$file")
if [ "$ignore_directory" != true ]; then
# 取临时目录后的相对路径
filename=$(echo "$file" | sed -E "s#^${temp_dir}/zip[0-9]*/##")
fi
target_file="$target_dir/$filename"
if [ "$ignore_directory" != true ]; then
# 提取目录信息
directory=$(dirname "$target_file")
# 创建目录(如果不存在)
mkdir -p "$directory"
fi
if [ "$merge_same_named" = true ]; then
# 合并文件信息
cat "$file" >> "$target_file"
rm -f "$file"
else
# 重置重复文件计数
counter=1
# 对同名文件添加后缀
while [ -e "$target_file" ]; do
target_file="$target_dir/${filename%.*}($counter).${filename##*.}"
counter=$((counter + 1))
done
mv "$file" "$target_file"
fi
done
# 压缩目标目录
cd $target_dir
zip -r $zip_flags "$target_zip" ./
# 清理临时目录
rm -rf "$temp_dir"
rm -rf "$target_dir"
}
# 合并 zip 文件
if [ "$performance_mode" = true ]; then
merge_zip "$target_zip" "$@"
else
# 解压缩并添加文件到目标 zip 文件中擦头
for file in "$@"; do
# 创建临时文件夹
unzip_dir=$(mktemp -d)
unzip $zip_flags "$file" -d "$unzip_dir"
# 合并到目标 zip 文件
find "$unzip_dir" -type f -print0 | while IFS= read -r -d '' file; do
add_file_to_zip "$target_zip" "$unzip_dir" "$file"
done
# 删除缓存,释放硬盘空间
rm -rf "$unzip_dir"
done
fi
echo "Zip 合并完成"
# 获取脚本结束的时间戳(毫秒)
end_time=$(date +%s%3N)
# 计算脚本执行时间(毫秒级)
duration=$(echo "scale=3; ($end_time - $start_time) / 1000" | bc)
# 打印处理时间
echo "脚本执行时间为:$duration 秒"
评论区