【发布时间】:2020-09-21 15:32:06
【问题描述】:
我的 Ubuntu 网络服务器上有大量 gzip 压缩文件,我需要将它们转换为 zip。我认为这可以通过脚本完成,但我应该使用什么语言,以及如何解压缩和重新压缩文件?
【问题讨论】:
我的 Ubuntu 网络服务器上有大量 gzip 压缩文件,我需要将它们转换为 zip。我认为这可以通过脚本完成,但我应该使用什么语言,以及如何解压缩和重新压缩文件?
【问题讨论】:
我会用 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。
【讨论】:
一个简单的 bash 脚本肯定是最简单的吗?这样您就可以调用tar 和zip 命令。
【讨论】:
在 unix 平台上最简单的解决方案可能是使用 fuse 和类似 archivemount (libarchive), http://en.wikipedia.org/wiki/Archivemount 的东西。
/iaw
【讨论】:
您可以为此目的使用node.js 和tar-to-zip。您需要做的就是:
如果没有,请使用 nvm 安装 node.js。
然后安装tar-to-zip:
npm i tar-to-zip -g
并将其用于:
tarzip *.tar.gz
您还可以通过编程将.tar.gz 文件转换为.zip。
您应该在本地安装async 和tar-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);
}
【讨论】:
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
【讨论】:
这里是基于这个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)
【讨论】:
这是基于@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)
【讨论】: