Linux下rar及zip压缩包中批量替换某文件脚本

简介:

本需求是自己负责的一个生产系统上,有大量以zip和rar结尾的压缩文件散落在文件系统的各个文件夹,先在需要把压缩包里包含某一个特定文件(如tftpd32.exe或Tftpd32.exe,版本较旧),全都替换成比较新的tftpd32.exe版本。压缩文件总数约5000个,需要替换的数量约1500个。

因为是生产环境,不敢轻易乱动,所以脚本考虑的因素就非常多,不允许中间执行过程出现异常,所以找到文件后实际执行替换操作之前做好备份,并且将操作过程记录日志。

以下几点需要考虑:

  • 分别处理zip和rar文件,为减低脚本的复杂程度,分作两个shell脚本。
  • rar在Linux下默认是没有安装解压缩工具,下载rarlinux-x64-5.2.0.tar.gz
  • zip包中文件含有中文文件名,unzip测试解压缩或列出内容时出现文件名乱码,原因是zip在压缩时不记录当时的编码格式。这个问题非常棘手,乱码打进压缩包是绝对不允许的,网上有几种解压办法有几种办法都不能很好的应对我的场景:并不需要实际解压zip文件,而只需使用 l ——列出文件列表、获取目录及文件名,d ——从压缩包中直接删除某个文件,a ——向压缩包添加一个文件。实际解压到文件系统上是不是乱码我们并不关心。
    最后的解决办法是使用p7zip工具,配合LANG变量解决。
  • 向压缩包里添加新文件时,要保持里面的目录结构,则必须在文件系统上存在同样的 相对目录/文件 。所以每次都要在脚本执行目录下创建临时目录tmp_dir,还要及时删除。但如果文件在压缩包的根目录下,这个临时目录就是当前脚本执行目录。
  • 有可能会存在一个压缩包中多个文件夹中包含不止一个tftpd32.exe文件。
  • 每个文件都有一个CRC值,处理文件名大小写不同但实质是同一个文件时有效。

以下脚本使用说明:

  • 变量说明

    • filelist 变量设定你所需要检查的压缩文件列表(绝对路径),可以通过find /your/dir/ -name *.rar | sort | uniq > testfile。与脚本在相同目录下
    • existlist 变量是从filelist文件中得到的包含特定文件的列表,脚本执行完后可以查看
    • errorlist 变量是从filelist文件列表中得到的不包含特定文件的列表,当然也有可能这个压缩文件本身不完整
    • filebak 变量指定要替换的那个压缩文件备份的目录
    • oldfile 指定要替换的那个文件名
    • newfile 指定新文件的文件名,注意这个文件一定要在脚本当前目录下
    • binrar,bin7z 指定解压缩命令目录,因为7zrar都不是CentOS自带的
    • fl 是filelist文件列表里的每一条记录
    • exist 压缩文件fl的内容列表里包含tftpd32.exe的记录,可能有多行
    • dirfiles 处理exist的结果,形如压缩包里的目录结构 your/dir/tftpd32.exe,可能有多行
    • df 是dirfiles中的单行记录,它的前面目录部分便是tmp_dir
  • 是否有必要root用户执行看个人情况,执行后部分文件的属主可能会变,可用chown user1.user1 -R /your/dir/恢复
  • 有部分zip文件无法使用7z,但文件本身正常,从日志可以看到error信息
  • tftpd32.exe区分大小写,如果要查找替换Tftpd32.exe请修改后在执行(确保grep没有-i选项)
  • 可以处理的情况

    • 压缩文件中无tftpd32.exe
    • 要替换的tftpd32.exe文件在压缩文件根目录下
    • 要替换的tftpd32.exe在嵌套子目录中
    • 压缩文件中存在多个tftpd32.exe
    • 压缩文件本身存在问题
  • 该脚本有一定的危险性(虽然已备份),在正式环境中运行之前一定要多做测试。并且运行一次之后,谨慎运行第二次,因为可能会导致备份被覆盖(可换备份目录)
  • 假如出现异常,要从备份文件恢复所有修改的文件,可以根据$existlistfilebak下的目录列表拼凑cp语句
  • 建议执行方法./rar_new.sh | tee your.log,事后可从your.log中查看日志

处理rar的脚本rar_new.sh:

#!/bin/bash

filelist="testfile"
# filelist="crm_rar.txt"
existlist="${filelist}.exist"
errorlist="${filelist}.not"
filebak="/crmbak/rarbak"
oldfile=tftpd32.exe                                                                                                                                          
newfile=tftpd32.exe
binrar="/usr/bin/rar"

IFS=$'\n'

echo "files list bellow have ${oldfile}:" > $existlist
echo "files list bellow do not have ${oldfile} or may have error:" > $errorlist

for fl in `cat $filelist`
  do 
    # ${oldfile} exist or not, file error or not
    exist=`$binrar l $fl |grep ${oldfile}`
    if [ $? -ne 0 ];then
       echo "$fl" >> $errorlist
       continue
    else
        # get extracting dir and filename, could be more than one file
       dirfiles=`echo "$exist" | awk '{for (i=5;i<=NF;i++) printf $i" " ; print ""}'`
    fi

#    echo "$exist"

    if [ "$dirfiles" != "" ];then
      echo "$fl" | tee -a $existlist
      # backup original file
      /bin/cp -af "$fl" "$filebak/"
      echo "--- $fl is backed up in $filebak"
      echo "    $dirfiles"

      for df in `echo "$dirfiles"`
        do
          # create temp directory to put new ${newfile} for compress
          tmp_dir=$( echo "$df" | awk -F '/' '{for(i=1;i<NF;i++) printf"%s/",$i} {print ""}' )
          if [ ${#tmp_dir} -ne 0 ];then
            mkdir -p "$tmp_dir" && cp -af ${newfile} "$tmp_dir"
          fi 
          # start delete old file and add new one
          $binrar d "$fl" "$tmp_dir"${oldfile} && $binrar a "$fl" "$tmp_dir"${newfile}
          if [ $? -ne 0 ];then                                                                                                                             
            echo "--- rar file $fl may have error, you SHOULD check it"
          fi

          if [ ${#tmp_dir} -ne 0 ];then
            rm -f "$tmp_dir"${newfile} && rmdir -p "$tmp_dir"
            if [ $? -ne 0 ];then
              echo "--- tmp_dir $tmp_dir delete fail"
            fi
          fi
        done

      echo "--- old deleted, new added"
    fi

  done

处理zip的脚本zip_new.sh:

#!/bin/bash

# filelist="test_filelist"
filelist="crm_zip.txt"
existlist="${filelist}.exist"
errorlist="${filelist}.not"
filebak="/crmbak/zipbak"
oldfile=Tftpd32.exe
newfile=tftpd32.exe
bin7z="/usr/bin/7z"

export LANG="zh_CN.GB18030"
IFS=$'\n'

echo "files list bellow have ${oldfile}:" > $existlist
echo "files list bellow do not have ${oldfile} or may have error:" > $errorlist

for fl in `cat $filelist`
  do 
    # ${oldfile} exist or not, file error or not
    exist=`$bin7z l $fl |grep ${oldfile}`
    if [ $? -ne 0 ];then
       echo "$fl" >> $errorlist
       continue
    else
        # get extracting dir and filename, could be more than one file
       dirfiles=`echo "$exist" | awk '{for (i=6;i<=NF;i++) printf $i" " ; print ""}'`
    fi

# echo ===== "$dirfiles"

    if [ "$dirfiles" != "" ];then
      echo "$fl" | tee -a $existlist
      # backup original file
      /bin/cp -af "$fl" "$filebak/"
      echo "--- $fl is backed up in $filebak"
      echo "    $dirfiles"

      for df in `echo "$dirfiles"`
        do
          # create temp directory to put new ${newfile} for compress
          tmp_dir=$( echo "$df" | awk -F '/' '{for(i=1;i<NF;i++) printf"%s/",$i} {print ""}' )
          if [ ${#tmp_dir} -ne 0 ];then
            mkdir -p "$tmp_dir" && cp -af ${newfile} "$tmp_dir"
          fi 
          # start delete old file and add new one
          $bin7z d "$fl" "$tmp_dir"${oldfile} && $bin7z a "$fl" "$tmp_dir"${newfile}
          if [ $? -ne 0 ];then                                                                                                                             
            echo "--- zip file $fl may have error, you SHOULD check it"
          fi

          if [ ${#tmp_dir} -ne 0 ];then
            rm -f "$tmp_dir"${newfile} && rmdir -p "$tmp_dir"
            if [ $? -ne 0 ];then
              echo "--- tmp_dir $tmp_dir delete fail"
            fi
          fi
        done

      echo "--- old deleted, new added"
    fi

  done

目录
相关文章
|
2月前
|
存储 安全 Unix
七、Linux Shell 与脚本基础
别再一遍遍地敲重复的命令了,把它们写进Shell脚本,就能一键搞定。脚本本质上就是个存着一堆命令的文本文件,但要让它“活”起来,有几个关键点:文件开头最好用#!/usr/bin/env bash来指定解释器,并用chmod +x给它执行权限。执行时也有讲究:./script.sh是在一个新“房间”(子Shell)里跑,不影响你;而source script.sh是在当前“房间”里跑,适合用来加载环境变量和配置文件。
405 9
|
Ubuntu Linux 网络安全
Linux系统初始化脚本
一款支持Rocky、CentOS、Ubuntu、Debian、openEuler等主流Linux发行版的系统初始化Shell脚本,涵盖网络配置、主机名设置、镜像源更换、安全加固等多项功能,适配单/双网卡环境,支持UEFI引导,提供多版本下载与持续更新。
276 0
Linux系统初始化脚本
|
2月前
|
存储 Shell Linux
八、Linux Shell 脚本:变量与字符串
Shell脚本里的变量就像一个个贴着标签的“箱子”。装东西(赋值)时,=两边千万不能有空格。用单引号''装进去的东西会原封不动,用双引号""则会让里面的$变量先“变身”再装箱。默认箱子只能在当前“房间”(Shell进程)用,想让隔壁房间(子进程)也能看到,就得给箱子盖个export的“出口”戳。此外,Shell还自带了$?(上条命令的成绩单)和$1(别人递进来的第一个包裹)等许多特殊箱子,非常有用。
289 2
|
4月前
|
存储 数据管理 Linux
区分Linux中.tar文件与.tar.gz文件的不同。
总之,".tar"文件提供了一种方便的文件整理方式,其归档但不压缩的特点适用于快速打包和解压,而".tar.gz"文件通过额外的压缩步骤,尽管处理时间更长,但可以减小文件尺寸,更适合于需要节约存储空间或进行文件传输的场景。用户在选择时应根据具体需求,考虑两种格式各自的优劣。
712 13
|
4月前
|
Web App开发 缓存 安全
Linux一键清理系统垃圾:释放30GB空间的Shell脚本实战​
这篇博客介绍了一个实用的Linux系统盘清理脚本,主要功能包括: 安全权限检查和旧内核清理,保留当前使用内核 7天以上日志文件清理和系统日志压缩 浏览器缓存(Chrome/Firefox)、APT缓存、临时文件清理 智能清理Snap旧版本和Docker无用数据 提供磁盘空间使用前后对比和大文件查找功能 脚本采用交互式设计确保安全性,适合定期维护开发环境、服务器和个人电脑。文章详细解析了脚本的关键功能代码,并给出了使用建议。完整脚本已开源,用户可根据需求自定义调整清理策略。
502 1
|
5月前
|
安全 Linux
Linux赋予文件000权限的恢复技巧
以上这些步骤就像是打开一扇锁住的门,步骤看似简单,但是背后却有着严格的逻辑和规则。切记,在任何时候,变更文件权限都要考虑安全性,不要无谓地放宽权限,那样可能
188 16
|
6月前
|
Java Linux
自定义linux脚本用于快速jar包启动、停止、重启
自定义linux脚本用于快速jar包启动、停止、重启
321 29
|
5月前
|
存储 Linux 数据处理
深入剖析Linux中一切即文件的哲学和重定向的机制
在计算机的奇妙世界中,Linux的这套哲学和机制减少了不同类型资源的处理方式,简化了抽象的概念,并蕴藏着强大的灵活性。就像变戏法一样,轻轻松松地在文件、程序与设备之间转换数据流,标准输入、输出、错误流就在指尖舞动,程序的交互和数据处理因此变得既高效又富有乐趣。
104 4
|
6月前
|
Ubuntu Linux
"unzip"命令解析:Linux下如何处理压缩文件。
总的来说,`unzip`命令是Linux系统下一款实用而方便的ZIP格式文件处理工具。本文通过简明扼要的方式,详细介绍了在各类Linux发行版上安装 `unzip`的方法,以及如何使用 `unzip`命令进行解压、查看和测试ZIP文件。希望本文章能为用户带来实际帮助,提高日常操作的效率。
894 12
|
6月前
|
Linux Shell
Centos或Linux编写一键式Shell脚本删除用户、组指导手册
Centos或Linux编写一键式Shell脚本删除用户、组指导手册
191 4