首页 > 程序资源 > shell 实现自释放多文件,自解压功能。

shell 实现自释放多文件,自解压功能。

起因是公司需求,要求我们的部署程序最终可以构建出一个文件,上传全新的纯内网服务器后,自动化部署。

而这个服务器是连 unzip 或 tar 都没有的环境,无奈只能通过 sh 脚本释放 tar 来解压自带的安装包了。

核心代码为如下两行:

tail --lines=+${attachment_start_line} "$0" > ./_tmp

为实现将 sh 脚本若干行后的内容提取到文件

head --bytes=${file_size} ./_tmp > ${file_name}

为实现将 文件的前若干字节提取到文件。

所以思路上就很简单了,这种所谓的自释放、自解压,其实网上已经有很多同类的脚本的,但普遍都只能释放一个文件,而我的这个需求,最少需要带两个文件,一个是 tar 的程序,一个是系统的安装包。

所以,自己就完善了一下功能,写出这套脚本,功能比较完善了,具有一下功能:

  1. 打包脚本(可以将制定目录下的所有文件都打包在一起)
  2. 解压后的 md5 校验,可以保证释放的文件是一致的
  3. 可以自定义添加释放后执行的脚本

具体代码可移步 github.gist

打包脚本:build-pack.sh

#!/bin/bash

# 如果没有 传递文件夹参数
source_dir=$1
if [ -z "${source_dir}" ]; then
    echo "请输入源文件夹路径"
    echo "Usage: $0 source_dir"
    exit 1
fi

# 需要压缩的文件列表
files=($(ls $source_dir))

# 自释放模板文件
unpack_tpl=./unpack-tpl.sh

# 生成结果
unpack_done=./unpack.sh

# 最终的临时文件
cp "${unpack_tpl}" "${unpack_done}"

# 获取标记行位置
attachment_start_line=($(awk '/^__ARCHIVE_BELOW__/ {; print NR; exit 0;}' "${unpack_done}"))
echo "Attachment Start Line: ${attachment_start_line}"

# 遍历文件获取文件尺寸头信息
file_info=()
for file in ${files[@]}; do
    echo -e "File Name: $file,\c"

    # 获取文件尺寸
    file_size=$(stat -c%s "${source_dir}/$file")
    echo -e " File Size: $file_size, File Md5: \c"

    # 获取文件 md5
    file_md5=$(md5sum "${source_dir}/${file}" | awk '{print $1}')
    echo -e "$file_md5\c"

    # 记录文件信息
    file_info[${#file_info[@]}]="${file},${file_size},${file_md5}"

    # 将文件追加到文件后面
    echo -e " Packing...\c"
    cat "${source_dir}/${file}" >>"${unpack_done}"
    echo " Done"
done

# 替换文件列表
echo -e "Save File Info To File...\c"
file_info=$(
    IFS=:
    echo "${file_info[*]}"
)
sed -i "${attachment_start_line}s/^__ARCHIVE_BELOW__/__ARCHIVE_BELOW__[${file_info}]/" "${unpack_done}"
echo -e "\nBuild Pack Done, File Save To ${unpack_done}"

# 查看结果头信息
# awk '/^__ARCHIVE_BELOW__/ {; print $1; exit 0;}' ./untardone.sh

解包脚本模板:unpack-tpl.sh

#!/bin/bash

# 获取解压目录
output_dir=$1
if [ "${output_dir}" == "" ]; then
    output_dir=$(mktemp -d)
fi
echo "Output Dir: ${output_dir}"

# 取出附件信息
attachment_info=($(awk '/^__ARCHIVE_BELOW__/ {files=gensub(/.*\[([^]]+)]/,"\\1",1,$0); print NR+1,files;exit 0;}' $0))

# 取出附件开始位置
attachment_start_line=${attachment_info[0]}
echo "Attachment Start Line: ${attachment_start_line}"

# 临时的过度文件
temp_file=$(mktemp)
echo "Unpack Temp File: ${temp_file}"

# 释放文件
tail -n+$attachment_start_line "$0" >${temp_file}

# 取出附件文件列表
attachment_files=(${attachment_info[1]//:/ })
# echo "Attachment Files: ${attachment_files[@]}"

# 获取一个文件信息
getFile() {
    # 获取文件信息
    file_info=$1

    # 拆分结构
    file_info=(${file_info//,/ })

    # 文件名
    file_name="${file_info[0]}"
    file_path="${output_dir}/${file_info[0]}"

    # 文件尺寸
    file_size=${file_info[1]}

    # 文件 hash
    file_md5=${file_info[2]}

    # 调试输出
    echo "File Name: ${file_name}, Save Path: ${file_path}, File Size: ${file_size}, File Md5: ${file_md5}"
}

# 以字节为单位读取文件
for file_info in ${attachment_files[@]}; do
    # 获取文件信息
    getFile $file_info

    # 读取文件头一段长度到文件
    echo "Read File To ${file_path} ..."
    head --bytes=${file_size} ${temp_file} >${file_path}

    # 重新计算 文件 md5
    echo -e "Calculate File Md5 \c"
    file_md5=$(md5sum ${file_path} | awk '{print $1}')
    if [ "${file_md5}" != "${file_md5}" ]; then
        echo "${file_path} Error"
    else
        echo "${file_md5} Success"
    fi

    # 重置临时文件
    echo "Reset Temp File ..."
    file_size=$(($file_size + 1))
    tail --bytes=+${file_size} ${temp_file} >"${temp_file}2"
    rm -rf ${temp_file}
    mv "${temp_file}2" ${temp_file}
done

# 删除临时文件
rm -rf ${temp_file}

###### 用户的自定义代码 开始 ######
#
# 文件释放后,并没有解压功能,需要自己打包时带上解压程序,并自己在下面调用程序解压
# After the file is released, there is no decompression function.
# You need to take the decompression program with you when you pack it,
# and call the program below to extract it.
#
# 以下为示例代码 The following is the sample code


# 进入临时文件夹
cd $output_dir

# 安装 tar
rpm -ivh --nodeps --force tar-1.30-5.an8.x86_64.rpm

# 解压出文件
echo "Untar ..."
tar -xvf *.tar.gz

# 执行安装脚本
echo "Sleep 10s, Execute Install Script ..."
sleep 10s

chmod +x *.sh
./install.sh

###### 用户的自定义代码 结束 以下勿动 ######
exit 0
__ARCHIVE_BELOW__

上一篇: Mac 下使用 PHPStorm 在开启 GPG 签名提交 Git 时失败的解决方案

下一篇: 因文件名包含不可见符号导致无法转移做种或辅种的解决方案

最近回复

标签