【发布时间】:2021-09-14 14:03:43
【问题描述】:
我在 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 为 bash,而不是
sh,以便pipefail成为可用选项。 -
或者,更好的是,完全停止使用任何 shell,只使用两个单独的
Popen对象,一个用于管道的每一侧,两者都使用shell=False。 -
顺便说一句,我不确定要求“正确”返回码的原始标题是否合适。有时,默认的 shell 行为 比
pipefail行为更“正确”——例如,当head在curl之前停止读取时,想想curl ... | head如何具有非零退出状态完成写入,导致 EPIPE,因此即使一切顺利,管道的左侧也会出现失败的退出状态。 -
ofc 你是绝对正确的!谢谢:)
标签: linux bash shell subprocess