Python调用Bash自动化RNA-seq流程时输出异常与文件写入问题
解决Python自动化fastq转fasta时的文件写入与subprocess错误问题
嘿,这个问题我太熟悉了!从你描述的情况来看,核心问题出在subprocess调用逻辑和文件写入的误区上——终端有输出说明转换命令本身是能跑的,但目标文件只写了'0',百分百是你把subprocess的退出状态码(成功时返回0)误写入文件了;而'str' object has no attr...的错误,通常是因为你给subprocess方法传了字符串参数,但它需要的是命令列表。
先理清两个核心错误原因
文件里只写了'0':
你大概率写了类似这样的代码:with open("output.fasta", "w") as f: f.write(subprocess.call("seqtk seq -a input.fastq"))但
subprocess.call()返回的是命令的退出状态码(0表示执行成功),不是命令的输出内容,所以你把数字0转成字符串写入了文件,这自然不是你要的fasta内容。'str' object has no attr...错误:
如果你用了subprocess.call()或subprocess.run()时加了shell=False(默认就是False),但直接传了完整的命令字符串,比如:subprocess.run("seqtk seq -a input.fastq", shell=False)这时候Python会把整个字符串当成一个命令去查找,显然找不到叫
seqtk seq -a input.fastq的命令,就会抛出类似找不到属性的错误(本质是参数类型不对)。正确的做法是把命令拆成列表形式。
正确的脚本实现(两种方式)
方式1:推荐用subprocess.run+命令列表(更安全,无shell注入风险)
这个方法会捕获命令的输出,然后写入文件,同时能处理错误:
import subprocess import glob # 遍历当前目录下所有fastq文件 for fastq_path in glob.glob("*.fastq"): # 生成对应的fasta文件名 fasta_path = fastq_path.replace(".fastq", ".fasta") # 构建命令列表:每个参数单独作为列表元素 cmd = ["seqtk", "seq", "-a", fastq_path] try: # 执行命令并捕获输出,text=True让输出是字符串而非字节 result = subprocess.run( cmd, check=True, # 命令执行失败时抛出异常 capture_output=True, # 捕获stdout和stderr text=True ) # 将捕获的stdout写入fasta文件 with open(fasta_path, "w") as f: f.write(result.stdout) print(f"✅ 成功转换: {fastq_path} → {fasta_path}") except subprocess.CalledProcessError as e: print(f"❌ 转换失败 {fastq_path}: {e.stderr.strip()}")
方式2:用shell=True(适合带管道/复杂命令的场景)
如果你的转换命令涉及管道、通配符等shell特性,可以用shell=True,但要注意命令是完整的字符串:
import subprocess import glob for fastq_path in glob.glob("*.fastq"): fasta_path = fastq_path.replace(".fastq", ".fasta") # 直接写完整的shell命令字符串 cmd = f"seqtk seq -a {fastq_path}" try: result = subprocess.run( cmd, check=True, capture_output=True, text=True, shell=True # 开启shell模式 ) with open(fasta_path, "w") as f: f.write(result.stdout) print(f"✅ 成功转换: {fastq_path} → {fasta_path}") except subprocess.CalledProcessError as e: print(f"❌ 转换失败 {fastq_path}: {e.stderr.strip()}")
额外方案:直接重定向stdout到文件(不需要捕获输出)
如果你不需要捕获输出做处理,也可以直接让命令的输出写入文件,效率更高:
import subprocess import glob for fastq_path in glob.glob("*.fastq"): fasta_path = fastq_path.replace(".fastq", ".fasta") cmd = ["seqtk", "seq", "-a", fastq_path] with open(fasta_path, "w") as f: # 把命令的stdout直接指向文件对象 exit_code = subprocess.run(cmd, stdout=f, text=True).returncode if exit_code == 0: print(f"✅ 成功转换: {fastq_path} → {fasta_path}") else: print(f"❌ 转换失败 {fastq_path}")
补充提醒
- 确保你已经安装了
seqtk(如果没有的话,可以用awk替代命令:awk 'NR%4==1{print ">"substr($0,2)}NR%4==2{print}' {fastq_path})。 - 优先用
subprocess.run而不是subprocess.call,前者是Python 3.5+推荐的API,功能更全面。
内容的提问来源于stack exchange,提问作者Ociocity
相关产品推荐
相关产品推荐

