You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用NamedTemporaryFile上下文管理器时Linux文件未关闭报错问题

问题描述

我今天遇到一个问题,简化后的代码在Mac上能正常运行,但在Linux上报错:

import tempfile
import subprocess
import os

with tempfile.NamedTemporaryFile() as tmp_file:
    with open(tmp_file.name, 'w') as writer:
        print("#!/bin/sh", file=writer)
        print("echo hi", file=writer)
    os.chmod(tmp_file.name, 0o511)
    subprocess.run([tmp_file.name], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

在Linux机器上收到错误:[Errno 26] Text file busy: '/tmp/tmp1y99vl6k',这说明调用subprocess时,writer的文件句柄实际并未关闭。

这是Python的预期行为吗?有没有办法在NamedTemporaryFile上下文内强制关闭文件,还是必须改用TemporaryDirectory?

我查到的相关说明:

当命名临时文件仍处于打开状态时,是否可以再次使用其名称打开该文件因平台而异(Unix系统可以;Windows系统不行)

解决方案

这是预期行为,根源在于不同Unix-like系统对"文件被打开时执行/重新打开"的处理逻辑不同:

  • macOS允许在文件被其他句柄打开的情况下执行该文件
  • Linux则会触发Text file busy错误,因为NamedTemporaryFile默认会保持文件打开状态(上下文管理器持有一个句柄),即使你自己的writer已经关闭。

解决方法1:在NamedTemporaryFile中关闭句柄后重新打开

可以手动关闭tmp_file的句柄,操作完成后再重新打开它(确保上下文结束时能正常清理临时文件):

import tempfile
import subprocess
import os

with tempfile.NamedTemporaryFile() as tmp_file:
    # 先关闭临时文件的句柄
    tmp_file.close()
    # 写入脚本内容
    with open(tmp_file.name, 'w') as writer:
        print("#!/bin/sh", file=writer)
        print("echo hi", file=writer)
    os.chmod(tmp_file.name, 0o511)
    # 执行脚本
    subprocess.run([tmp_file.name], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    # 重新打开文件,确保上下文管理器能正常删除它
    tmp_file = open(tmp_file.name, 'r')

解决方法2:使用delete=False参数,手动清理文件

如果不需要上下文自动删除文件,可以指定delete=False,操作完成后手动删除临时文件:

import tempfile
import subprocess
import os

tmp_file = tempfile.NamedTemporaryFile(delete=False)
tmp_file.close()
try:
    with open(tmp_file.name, 'w') as writer:
        print("#!/bin/sh", file=writer)
        print("echo hi", file=writer)
    os.chmod(tmp_file.name, 0o511)
    subprocess.run([tmp_file.name], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
finally:
    os.unlink(tmp_file.name)

解决方法3:改用TemporaryDirectory

如果上面的方法都不符合需求,创建临时目录再在里面生成脚本文件也是一个稳妥的方案:

import tempfile
import subprocess
import os

with tempfile.TemporaryDirectory() as tmp_dir:
    script_path = os.path.join(tmp_dir, "script.sh")
    with open(script_path, 'w') as writer:
        print("#!/bin/sh", file=writer)
        print("echo hi", file=writer)
    os.chmod(script_path, 0o511)
    subprocess.run([script_path], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

内容的提问来源于stack exchange,提问作者cel

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 07:10:11