You are trying to use a Bash feature (${variable/pattern/substitution}
) in sh
code. You could use subprocess.run
with executable='/bin/bash'
but there is actually absolutely no reason to run the loop in the shell.
import glob
import subprocess
for file in glob.glob('*.sam'):
with open(file.replace('.sam', '.stat'), 'w') as output:
subprocess.run(['samtools', 'flagstat', file],
stdout=output, check=True)
The check=True
is assuming that samtools
returns a useful exit code, and that you want to know if it fails.
Generally speaking, you should run as little code as possible in a subprocess
because it's basically happening outside of your control. The parts you write yourself in Python (or better yet import
from a well-maintained library) can be properly managed by your Python code, whereas the communications with an external process will necessarily be limitede and constrained.
Maybe see also Running Bash commands from Python for why to avoid os.system
and the precise meaning of check=True
, and Difference between sh and bash. Actual meaning of 'shell=True' in subprocess explains why you want to avoid invoking a shell if you can.
For completeness' sake, here is a syntactically correct, sh
-compatible for
loop:
for f in *.sam; do
samtools flagstat "$f" >"${f%.sam}.stat"
done
Notice the quotes.
(If you absolutely want a one-liner, you can replace the newline before done
with a semicolon.)