J'utilise le subprocess.Popen
appeler, et dans une autre question, j'ai découvert que j'avais mal compris comment Python générait des arguments pour la ligne de commande.
Ma question
Existe-t-il un moyen de savoir quelle était la ligne de commande réelle?
Exemple de code: -
proc = subprocess.popen(....)
print "the commandline is %s" % proc.getCommandLine()
Comment écririez-vous getCommandLine
?
Cela dépend de la version de Python que vous utilisez. En Python3. , l'argument est enregistré dans proc.args
:
proc = subprocess.Popen(....)
print("the commandline is {}".format(proc.args))
En Python2.7, le args
non enregistré , il est simplement passé à d'autres fonctions comme _execute_child
. Donc, dans ce cas, la meilleure façon d'obtenir la ligne de commande est de l'enregistrer lorsque vous l'avez:
proc = subprocess.Popen(shlex.split(cmd))
print "the commandline is %s" % cmd
Notez que si vous avez la liste arguments (comme le type de chose retourné par shlex.split(cmd)
, alors vous pouvez récupérer la chaîne de ligne de commande, cmd
en utilisant la fonction non documentée subprocess.list2cmdline
:
In [14]: import subprocess
In [15]: import shlex
In [16]: cmd = 'foo -a -b --bar baz'
In [17]: shlex.split(cmd)
Out[17]: ['foo', '-a', '-b', '--bar', 'baz']
In [18]: subprocess.list2cmdline(['foo', '-a', '-b', '--bar', 'baz'])
Out[19]: 'foo -a -b --bar baz'
La bonne réponse à ma question est qu'il n'y a pas de ligne de commande. Le point de sous-processus est qu'il fait tout via IPC. Le list2cmdline se rapproche le plus possible, mais en réalité la meilleure chose à faire est de regarder la liste "args", et sachez simplement que ce sera argv dans le programme appelé.
Belle méthode évolutive
J'utilise quelque chose comme ça:
#!/usr/bin/env python3
import os
import shlex
import subprocess
import sys
def run_cmd(cmd, cwd=None, extra_env=None, extra_paths=None, dry_run=False):
if extra_env is None:
extra_env = {}
newline_separator = ' \\\n'
out = []
kwargs = {}
env = os.environ.copy()
# cwd
if 'cwd' is not None:
kwargs['cwd'] = cwd
# extra_env
env.update(extra_env)
for key in extra_env:
out.append('{}={}'.format(shlex.quote(key), shlex.quote(extra_env[key])) + newline_separator)
# extra_paths
if extra_paths is not None:
path = ':'.join(extra_paths)
if 'PATH' in env:
path += ':' + env['PATH']
env['PATH'] = path
out.append('PATH="{}:${{PATH}}"'.format(':'.join(extra_paths)) + newline_separator)
# Command itself.
for arg in cmd:
out.append(shlex.quote(arg) + newline_separator)
# Print and run.
kwargs['env'] = env
print('+ ' + ' '.join(out) + ';')
if not dry_run:
subprocess.check_call(cmd, **kwargs)
run_cmd(
sys.argv[1:],
cwd='/bin',
extra_env={'ASDF': 'QW ER'},
extra_paths=['/some/path1', '/some/path2']
)
Exemple d'exécution:
./a.py echo 'a b' 'c d'
Production:
+ ASDF='QW ER' \
PATH="/some/path1:/some/path2:${PATH}" \
echo \
'a b' \
'c d' \
;
a b c d
Résumé des fonctionnalités:
+
à des commandes comme sh -x
pour que les utilisateurs puissent facilement différencier les commandes de leur sortiecd
, et des variables d'environnement supplémentaires si elles sont données à la commande. Celles-ci ne s'impriment que si elles sont fournies, générant une commande Shell minimale.Tout cela permet aux utilisateurs de copier facilement les commandes manuellement pour les exécuter en cas d'échec ou pour voir ce qui se passe.
Testé sur Python 3.5.2, Ubuntu 16.04. GitHub en amont .