linux - 如果管道的左侧失败,则使从 subprocess.Popen 启动的 shell 管道失败
问题描述
我在 python 中使用 subprocess.popen 运行 bash 命令:
cmd = "bwa-mem2/bwa-mem2 mem -R \'@RG\\tID:2064-01\\tSM:2064-01\\tLB:2064-01\\tPL:ILLUMINA\\tPU:2064-01\' reference_genome/human_g1k_v37.fasta BHYHT7CCXY.RJ-1967-987-02.2_1.fastq BHYHT7CCXY.RJ-1967-987-02.2_2.fastq -t 14 | samtools view -bS -o dna_seq/aligned/2064-01/2064-01.6.bam -"
process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
问题是即使第一个命令失败,我也会得到返回码 0。我已经用谷歌搜索并发现了 pipefail ,这似乎是我应该使用的。
但是,我不明白在哪里写它。我努力了:
"set -o pipefail && bwa-mem2/bwa-mem2 mem -R \'@RG\\tID:2064-01\\tSM:2064-01\\tLB:2064-01\\tPL:ILLUMINA\\tPU:2064-01\' reference_genome/human_g1k_v37.fasta BHYHT7CCXY.RJ-1967-987-02.2_1.fastq BHYHT7CCXY.RJ-1967-987-02.2_2.fastq -t 14 | samtools view -bS -o dna_seq/aligned/2064-01/2064-01.6.bam -"
给出:/bin/sh: 1: set: Illegal option -o pipefail
有什么想法我应该如何整合它?
编辑:
我不确定在回复答案时编辑我的答案是否正确?评论中没有足够的字符来回复:/
无论如何,我在没有shell=True
@Charles Duffy 的情况下尝试了你的第二种方法。
(cmd_1 和 cmd_2 等于您在解决方案中写的内容)
这是我使用的代码:
try:
p1 = Popen(shlex.split(cmd_1), stdout=PIPE)
p2 = Popen(shlex.split(cmd_2), stdin=p1.stdout, stdout=PIPE, stderr=STDOUT, text=True)
p1.stdout.close()
output, error = p2.communicate()
p1.wait()
rc_1 = p1.poll()
rc_2 = p2.poll()
print("rc_1:", rc_1)
print("rc_2:", rc_2)
if rc_1 == 0 and rc_2 == 0:
self.log_to_file("DEBUG", "# Process ended with returncode = 0")
if text: self.log_to_file("INFO", f"{text} succesfully
else:
print("Raise exception")
raise Exception(f"stdout: {output} stderr: {error}")
except Exception as e:
print(f"Error: {e} in misc.run_command()")
self.log_to_file("ERROR", f"# Process ended with returncode != 0, {e}")
这是我通过重命名一个文件故意导致错误时得到的结果:
[E::main_mem] failed to open file `/home/jonas/BASE/dna_seq/reads/2064-01/test_BHYHT7CCXY.RJ-1967-987-02.2_2.fastq.gz'.
free(): double free detected in tcache 2
rc_1: -6
rc_2: 0
Raise exception
Error: stdout: stderr: None in misc.run_command()
ERROR: # Process ended with returncode != 0, stdout: stderr: None
它似乎捕获了错误的返回码。
但是为什么是stdout
空的stderr= None
?如何在进程成功和失败时捕获输出以将其记录到记录器中?
解决方案
一、带壳
而不是让默认指定,shell=True
明确指定以确保这是一个可用的功能:sh
bash
pipefail
shell_script = r'''
set -o pipefail || exit
bwa-mem2/bwa-mem2 mem \
-R '@RG\tID:2064-01\tSM:2064-01\tLB:2064-01\tPL:ILLUMINA\tPU:2064-01' \
reference_genome/human_g1k_v37.fasta \
BHYHT7CCXY.RJ-1967-987-02.2_1.fastq \
BHYHT7CCXY.RJ-1967-987-02.2_2.fastq \
-t 14 \
| samtools view -bS \
-o dna_seq/aligned/2064-01/2064-01.6.bam -
'''
process = subprocess.Popen(["bash", "-c", shell_script],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
这行得通,但它不是最好的选择。
二、完全没有外壳
p1 = subprocess.Popen(
['bwa-mem2/bwa-mem2', 'mem',
'-R', r'@RG\tID:2064-01\tSM:2064-01\tLB:2064-01\tPL:ILLUMINA\tPU:2064-01',
'reference_genome/human_g1k_v37.fasta',
'BHYHT7CCXY.RJ-1967-987-02.2_1.fastq',
'BHYHT7CCXY.RJ-1967-987-02.2_2.fastq', '-t', '14'],
stdout=subprocess.PIPE)
p2 = subprocess.Popen(
['samtools', 'view', '-bS',
'-o', 'dna_seq/aligned/2064-01/2064-01.6.bam', '-'],
stdin=p1.stdout,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True)
p1.stdout.close()
output, _ = p2.communicate() # let p2 finish running
p1.wait() # ensure p1 has properly exited
print(f'bwa-mem2 exited with status {p1.returncode}')
print(f'samtools exited with status {p2.returncode}')
...这使您可以p1.returncode
单独检查p2.returncode
。
推荐阅读
- python - Tkinter messagedialog askyesno 带有复选框?
- java - Hibernate 只在不应该返回的时候返回一条记录
- bigcommerce - 在 BigCommerce 中访问店面的元字段
- java - spring boot 无法调用存储库,因为存储库为空
- python - 组合两个数据框,将值加到相应的名称中
- node.js - 我在 PassportJS 中使用的异步函数中的引用错误
- dialogflow-es - Google Assistant 上的 userStorage 奇怪的格式
- python - 如何在这段代码中调用 get_data 函数
- python - 使用正则表达式在匹配之前立即查找字符
- amazon-web-services - AWS Workspace 无法启动