Redirecionar comando para entrada de outro em Python
Pergunta
Eu gostaria de replicar isso em python:
gvimdiff <(hg cat file.txt) file.txt
(hg cat file.txt gera a versão confirmada mais recentemente de file.txt)
Eu sei como canalizar o arquivo para o gvimdiff, mas ele não aceita outro arquivo:
$ hg cat file.txt | gvimdiff file.txt -
Too many edit arguments: "-"
Chegando à parte do python...
# hgdiff.py
import subprocess
import sys
file = sys.argv[1]
subprocess.call(["gvimdiff", "<(hg cat %s)" % file, file])
Quando o subprocesso é chamado, ele simplesmente passa <(hg cat file)
para gvimdiff
como um nome de arquivo.
Então, existe alguma maneira de redirecionar um comando como o bash faz?Para simplificar, apenas cat um arquivo e redirecione-o para diff:
diff <(cat file.txt) file.txt
Solução
Pode ser feito.A partir do Python 2.5, entretanto, este mecanismo é específico do Linux e não é portátil:
import subprocess
import sys
file = sys.argv[1]
p1 = subprocess.Popen(['hg', 'cat', file], stdout=subprocess.PIPE)
p2 = subprocess.Popen([
'gvimdiff',
'/proc/self/fd/%s' % p1.stdout.fileno(),
file])
p2.wait()
Dito isto, no caso específico do diff, você pode simplesmente pegar um dos arquivos do stdin e eliminar a necessidade de usar a funcionalidade semelhante ao bash em questão:
file = sys.argv[1]
p1 = subprocess.Popen(['hg', 'cat', file], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['diff', '-', file], stdin=p1.stdout)
diff_text = p2.communicate()[0]
Outras dicas
Existe também o módulo de comandos:
import commands
status, output = commands.getstatusoutput("gvimdiff <(hg cat file.txt) file.txt")
Há também o conjunto de funções popen, se você quiser realmente entender os dados de um comando enquanto ele está em execução.
Na verdade, este é um exemplo no documentos:
p1 = Popen(["dmesg"], stdout=PIPE)
p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]
o que significa para você:
import subprocess
import sys
file = sys.argv[1]
p1 = Popen(["hg", "cat", file], stdout=PIPE)
p2 = Popen(["gvimdiff", "file.txt"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]
Isso remove o uso dos bits /proc/self/fd específicos do Linux, fazendo com que provavelmente funcione em outros dispositivos como Solaris e BSDs (incluindo MacOS) e talvez até funcione no Windows.
Acabei de perceber que você provavelmente está procurando uma das funções popen.
de: http://docs.python.org/lib/module-popen2.html
Popen3 (cmd [, bufsize [, modo]]) executa o CMD como um subprocesso.Retorna os objetos do arquivo (child_stdout, child_stdin, child_stderr).
Namaste, Mark