如何用Python tarfile处理subprocess输出的tar归档流?
问题:用Python的subprocess和tarfile实现tar管道功能
我有一个类似ssh的nomad alloc exec命令,可在远端执行tar命令并获取其stdout输出。想要实现Shell中ssh server tar cf - file1 file2 | tar xf - -C destinationdir的tar管道功能:用subprocess作为管道左侧,右侧使用tarfile而非额外的subprocess或Shell。
尝试了以下代码:
import os import subprocess import tarfile os.system("echo 123 > /tmp/1 ; mkdir -p /tmp/dir") sourcefile = "/tmp/1" destinationdir = "/tmp/dir" with subprocess.Popen([*"tar -cf - --".split(), sourcefile], stdout=subprocess.PIPE) as pp: with tarfile.open(fileobj=pp.stdout) as tf: tf.extractall(destinationdir)
但执行时报错:
$ python3 ./test.py tar: Removing leading `/' from member names Traceback (most recent call last): File "/dev/shm/.1000.home.tmp.dir/./test.py", line 9, in <module> with tarfile.open(fileobj=pp.stdout) as tf: File "/usr/lib/python3.10/tarfile.py", line 1630, in open saved_pos = fileobj.tell() OSError: [Errno 29] Illegal seek
原因是tarfile默认会尝试对输入文件对象执行seek/tell操作,但subprocess的stdout管道是单向的、不可定位的流,不支持这些操作。
解决方案
使用tarfile的流式读取模式mode='r|*',这个模式专门用于处理不可seek的输入流,不需要定位文件指针。修改后的代码如下:
import os import subprocess import tarfile os.system("echo 123 > /tmp/1 ; mkdir -p /tmp/dir") sourcefile = "/tmp/1" destinationdir = "/tmp/dir" # 启动tar命令生成流式归档 with subprocess.Popen( ["tar", "-cf", "-", "--", sourcefile], stdout=subprocess.PIPE, stderr=subprocess.PIPE # 可选:捕获tar的stderr输出,避免干扰终端 ) as pp: # 使用流式模式打开tar归档,不需要seek操作 with tarfile.open(fileobj=pp.stdout, mode='r|*') as tf: tf.extractall(destinationdir) # 可选:检查tar命令是否正常退出 if pp.returncode != 0: stderr = pp.stderr.read().decode() raise RuntimeError(f"tar命令执行失败: {stderr}")
关键修改点:
- 将
tarfile.open()的mode参数指定为'r|*',这是tarfile的流式读取模式,会逐块处理输入,不需要对文件对象执行seek操作。 - 可选:添加
stderr=subprocess.PIPE捕获tar命令的错误输出,方便排查问题。 - 可选:检查subprocess的返回码,确保远端tar命令执行正常。
内容的提问来源于stack exchange,提问作者KamilCuk
相关产品推荐
相关产品推荐

