我偶尔会得到文件名以 ISO-8859-1 或其他 Unicode 之前的方案编码的 tarball。我的系统使用 UTF-8,因此当我使用常用选项 ( tar xvf foo.tar
) 解压这些存档时,我最终会得到一个充满 mojibake 文件名的目录。
到目前为止我一直在使用convmv
将文件名转换为 UTF-8后他们已被提取。这有点不方便,因为我要么需要调用convmv
每个受影响的文件,要么将文件解压到新目录中,convmv
在整个目录上运行,然后将文件移动到我最初想要的位置。如果无法将此功能编码到 shell 脚本中,是否有某种方法可以在解压存档文件名时将其即时转换为 UTF-8?
答案1
这是一个小tar
文件提取器,它在提取之前修改内存中的名称:
#!/usr/bin/python27
import tarfile
def transform(data):
u = data.decode('latin1')
return u.encode('utf8')
tar = tarfile.open('archive.tar')
for m in tar.getmembers():
m.name = transform(m.name)
tar.extractall()
警告:与 GNU 不同tar
,该提取器不会剥离前导/
。要么向该提取器添加检查逻辑,要么tar
在使用tar -t
.
答案2
托马斯·埃克的回答几乎对我有用,除了调用getmembers
似乎将整个存档读入内存,而我拥有的 tar 文件太大了。这是一次读取一个文件的修改版本。名称转换也不同,因为在我的 tar 文件中,文件名显示有代理字符;我不确定这是否普遍适用。
#!/usr/bin/env python3
import tarfile
import sys
from pathlib import Path
def transform(data):
try:
data.encode('utf-8')
return data
except UnicodeEncodeError as err:
u = data.encode('utf-8', 'surrogateescape')
v = u.decode('latin-1')
print(f'Replaced filename: {v}')
v.encode('utf-8') # check that it can be encoded
return v
tar = tarfile.open(sys.argv[1])
while (m := tar.next()) is not None:
if m.name == '.':
continue
m.name = transform(m.name)
path = Path(m.name)
try:
if path.stat().st_size == m.size:
print(f'Already exists with the same size: skipping {m.name}')
continue
else:
print(f'Size mismatch, extracting: {m.name}', flush=True)
except FileNotFoundError:
print(f'About to extract {m.name}', flush=True)
tar.extract(m)
print(f'Extracted {m.name}')