obtém o prompt do shell em python

3

Eu quero obter o prompt de shell (zsh) em um script python. Simplesmente usando

import os
prompt = os.environ['PS1']

parece não ser o caminho certo, porque PS1 geralmente não é encaminhado para subprocessos. Da mesma maneira, env | grep PS em um shell falha.

Concluí que provavelmente deveria iniciar um shell interativo como subprocesso e consultar seu prompt. De um shell eu posso fazer apenas

zsh -c -i 'echo $PS1'

(deve ser aspas simples, aspas duplas falham)

Eu tentei fazer o mesmo do python (2.7) com subprocess assim:

print subprocess.check_output(['-i','-c',r"'echo $PS1'"],executable="/bin/zsh")

Isso falha com

subprocess.CalledProcessError: Command '['-i', '-c', "'echo $PS1'"]' returned non-zero exit status 127

Eu acho que isso não é por causa do $PS1 , mas devido à maneira como eu forneço a parte echo como argumento, porque também ecoa as strings nuas dessa maneira falha.

Experimentando várias combinações acabei com

prompt =  subprocess.check_output("""zsh -c -i 'echo $PS1'""",shell=True,executable="/bin/zsh")

que parece fazer o trabalho, mas parece errado para mim, pois isso está iniciando um shell e, nesse shell, chamando ainda outro shell com -c -i 'echo $PS1' .

Qual é a maneira correta de obter o prompt do shell.

    
por pseyfert 10.06.2016 / 16:49

2 respostas

1
print subprocess.check_output(['zsh','-i','-c','echo $PS1'])

Ao executar zsh de outro shell, as cotas em torno de echo $PS1 são necessárias para que a sequência inteira seja passada como o único argumento após -c . Eles tinham que ser citações simples porque nas aspas duplas, o primeiro shell teria expandido $PS1 .

No Python, o comando inteiro é uma única string, por isso é citado como qualquer outra string. Adicionar um segundo conjunto é como digitar 'echo $PS1' (com as aspas) em zsh - o shell procura e não consegue localizar um executável chamado 'echo $PS1' .

    
por 10.06.2016 / 17:50
1

Acho que a maneira correta é chamar o subprocesso da seguinte forma:

>>> prompt = subprocess.check_output("""echo $PS1""",shell=True,executable="/bin/zsh")

Então você pode verificar o resultado por >>> prompt Enter ou você pode usar a chamada para ver os resultados diretamente:

>>> subprocess.call("""echo $PS1""",shell=True,executable="/bin/zsh")

Então você não precisa chamar zsh no próprio comando.

Para se comunicar interativamente Popen pode ser usado:

>>> Popen(["/bin/zsh"], stdout=PIPE).communicate()[0]
SHELL_PROMPT% echo $PS1    
SHELL_PROMPT% exit  # exit to see the result of command   

Para saber mais sobre isso, consulte Subprocesso

Observe também o aviso sobre o uso de shell=True do link acima:

Warning: Executing shell commands that incorporate unsanitized input from an untrusted source makes a program vulnerable to shell injection, a serious security flaw which can result in arbitrary command execution. For this reason, the use of shell=True is strongly discouraged in cases where the command string is constructed from external input:

>>> from subprocess import call
>>> filename = input("What file would you like to display?\n")
What file would you like to display?
non_existent; rm -rf / #
>>> call("cat " + filename, shell=True) # Uh-oh. This will end badly...
shell=False does not suffer from this vulnerability; the above Note may be helpful in getting code using shell=False to work.
    
por 10.06.2016 / 17:47