【问题标题】:Convert tar.gz to zip将 tar.gz 转换为 zip
【发布时间】:2020-09-21 15:32:06
【问题描述】:

我的 Ubuntu 网络服务器上有大量 gzip 压缩文件,我需要将它们转换为 zip。我认为这可以通过脚本完成,但我应该使用什么语言,以及如何解压缩和重新压缩文件?

【问题讨论】:

    标签: linux ubuntu zip gzip


    【解决方案1】:

    我会用 bash(1) 单线:

    for f in *.tar.gz;\
    do rm -rf ${f%.tar.gz} ;\
    mkdir ${f%.tar.gz} ;\
    tar -C ${f%.tar.gz} zxvf $f ;\
    zip -r ${f%.tar.gz} $f.zip ;\
    rm -rf ${f%.tar.gz} ;\
    done
    

    它不是很漂亮,因为我不擅长bash(1)。请注意,这会破坏很多目录,因此请确保在执行此操作之前知道它的作用。

    有关${foo%bar} 语法的更多详细信息,请参阅the bash(1) reference card

    【讨论】:

    • 这基本上是我的建议,但你比我更快地提出一个例子。 :)
    • @Sven,不用费心去测试是节省时间的好方法。 :)
    【解决方案2】:

    一个简单的 bash 脚本肯定是最简单的吗?这样您就可以调用tarzip 命令。

    【讨论】:

      【解决方案3】:

      在 unix 平台上最简单的解决方案可能是使用 fuse 和类似 archivemount (libarchive), http://en.wikipedia.org/wiki/Archivemount 的东西。

      /iaw

      【讨论】:

        【解决方案4】:

        您可以为此目的使用node.jstar-to-zip。您需要做的就是:

        如果没有,请使用 nvm 安装 node.js。

        然后安装tar-to-zip

        npm i tar-to-zip -g
        

        并将其用于:

        tarzip *.tar.gz
        

        您还可以通过编程将.tar.gz 文件转换为.zip。 您应该在本地安装asynctar-to-zip

        npm i async tar-to-zip
        

        然后用内容创建converter.js

        #!/usr/bin/env node
        
        'use strict';
        
        const fs = require('fs');
        const tarToZip = require('tar-to-zip');
        const eachSeries = require('async/eachSeries');
        const names = process.argv.slice(2);
        
        eachSeries(names, convert, exitIfError);
        
        function convert(name, done) {
            const {stdout} = process;
            const onProgress = (n) => {
                stdout.write(`\r${n}%: ${name}`);
            };
            const onFinish = (e) => {
                stdout.write('\n');
                done();
            };
        
            const nameZip = name.replace(/\.tar\.gz$/, '.zip');    
            const zip = fs.createWriteStream(nameZip)
                .on('error', (error) => {
                    exitIfError(error);
                    fs.unlinkSync(zipPath);
                });
        
            const progress = true;
            tarToZip(name, {progress})
                .on('progress', onProgress)
                .on('error', exitIfError)
                .getStream()
                .pipe(zip)
                .on('finish', onFinish);
        }
        
        function exitIfError(error) {
            if (!error)
                return;
        
            console.error(error.message);
            process.exit(1);
        }
        

        【讨论】:

          【解决方案5】:

          Zipfile 很方便,因为它们提供对文件的随机访问。 tar 文件只是顺序的。

          我对此转换的解决方案是这个 shell 脚本,它通过 tar(1) "--to-command" 选项调用自己。 (我更喜欢这样,而不是拥有 2 个脚本)。但我承认“untar and zip -r”比这更快,因为 zipnote(1) 不能就地工作,很遗憾。

          #!/bin/zsh -feu
          
          ## Convert a tar file into zip:
          
          usage() {
              setopt POSIX_ARGZERO
              cat <<EOF
              usage: ${0##*/} [+-h] [-v] [--] {tarfile} {zipfile}"
          
          -v verbose
          -h print this message
          converts the TAR archive into ZIP archive.
          EOF
              unsetopt POSIX_ARGZERO
          }
          
          while getopts :hv OPT; do
              case $OPT in
                  h|+h)
                      usage
                      exit
                      ;;
                  v)
                      # todo: ignore TAR_VERBOSE from env?
                      # Pass to the grand-child process:
                      export TAR_VERBOSE=y
                      ;;
                  *)
                      usage >&2
                      exit 2
              esac
          done
          shift OPTIND-1
          OPTIND=1
          
          # when invoked w/o parameters:
          if [ $# = 0 ] # todo: or stdin is not terminal
          then
              # we are invoked by tar(1)
              if [ -n "${TAR_VERBOSE-}" ]; then echo $TAR_REALNAME >&2;fi
              zip --grow --quiet $ZIPFILE -
              # And rename it:
              # fixme: this still makes a full copy, so slow.
              printf "@ -\n@=$TAR_REALNAME\n" | zipnote -w $ZIPFILE
          else
              if [ $# != 2 ]; then usage >&2; exit 1;fi
              # possibly: rm -f $ZIPFILE
              ZIPFILE=$2 tar -xaf $1 --to-command=$0
          fi
          

          【讨论】:

            【解决方案6】:

            这里是基于这个answer here的python解决方案:

            import sys, tarfile, zipfile, glob
            
            def convert_one_archive(file_name):
                out_file = file_name.replace('.tar.gz', '.zip')
                with tarfile.open(file_name, mode='r:gz') as tf:
                    with zipfile.ZipFile(out_file, mode='a', compression=zipfile.ZIP_DEFLATED) as zf:
                        for m in tf.getmembers():
                            f = tf.extractfile( m )
                            fl = f.read()
                            fn = m.name
                            zf.writestr(fn, fl)
            
            for f in glob.glob('*.tar.gz'):
                convert_one_archive(f)
            

            【讨论】:

              【解决方案7】:

              这是基于@Brad Campbell 答案的脚本,它适用于作为命令参数传递的文件,适用于其他 tar 文件类型(未压缩或 tarfile 支持的其他压缩类型),并处理源 tar 文件中的目录。如果源文件包含转换为常规文件的符号链接或硬链接,它也会打印警告。对于符号链接,链接在转换过程中被解析。如果链接目标不在 tar 中,这可能会导致错误;从安全的角度来看,这也有潜在的危险,所以用户要小心。

              #!/usr/bin/python
              
              import sys, tarfile, zipfile, glob, re
              
              def convert_one_archive(in_file, out_file):
                  with tarfile.open(in_file, mode='r:*') as tf:
                      with zipfile.ZipFile(out_file, mode='a', compression=zipfile.ZIP_DEFLATED) as zf:
                          for m in [m for m in tf.getmembers() if not m.isdir()]:
                              if m.issym() or m.islnk():
                                  print('warning: symlink or hardlink converted to file')
                              f = tf.extractfile(m)
                              fl = f.read()
                              fn = m.name
                              zf.writestr(fn, fl)
              
              for in_file in sys.argv[1:]:
                  out_file = re.sub(r'\.((tar(\.(gz|bz2|xz))?)|tgz|tbz|tbz2|txz)$', '.zip', in_file)
                  if out_file == in_file:
                      print(in_file, '---> [skipped]')
                  else:
                      print(in_file, '--->', out_file)
                      convert_one_archive(in_file, out_file)
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2017-01-08
                • 1970-01-01
                • 2020-03-16
                • 2020-06-15
                • 2011-04-22
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多