I think it makes sense to prefer this hypothetical API:
subprocess.run_escaped("tac -- %s | grep 1 > %s", "foo.txt", "bar.txt")
over this: with open("bar.txt", "w") as outfile:
tac = subprocess.Popen(["tac", "--", "foo.txt"], stdout=subprocess.PIPE)
grep = subprocess.Popen(["grep", "1"], stdin=tac.stdout, stdout=outfile)
tac.wait()
grep.wait()
(In practice the shell grammar is so grotesque that I'd never trust it to be 100% correct. But the idea is nice.)