Analyse ligne de commandes
Le
Pierre Maurette
Bonjour,
Je cherche à réutiliser l'existant concernant l'analyse primaire de la
ligne de commandes, en fait le découpage. J'ai une ligne de commande
sous forme de chaîne de caractères:
r'rsync -a "pierre@UBUNTU64-V:/home/pierre maurette/SITES/"'
et je veux en tirer une liste de chaînes. Le problème évidemment se
situe au niveau des arguments contenant des espaces. C'est encore assez
facile de traiter les '"', mais si on ajoute les échappements et
peut-être d'autres subtilités, ça risque de se compliquer. D'où ma
volonté d'utiliser ce qui existe.
Je n'ai pas trouvé dans Python où est fait ce découpage. En fait, je ne
sais pas si c'est fait par Python ou par l'OS. Pour un exécutable
compilé, c'est l'OS.
Pour l'instant, j'utilise une méthode un peu bourri, je lance une
instance de Python avec la ligne de commandes et je récupère sys.argv.
J4ai survolé optparse (que j'utilise) et getopt (que je n'utilise pas)
mais je n'ai rien vu, il semble que ces modules se situent en aval de
l'analyse primaire.
Y a-t-il une fonction qui me ferait ça simplement ? Je me suis résolu à
poser la question parce que j'ai constaté qu'en Python je passais pas
mal de temps à réinventer la roue, alors qu'il existe beaucoup de
ressources que j'ignore, ou pire que j'ai oublié après les avoir
utilisées une fois grâce à Google.
Pour info mon code de test avec la méthode bourrin (le but de ce petit
outil est de gérer une ruche de commandes chiantes à mémoriser et à
saisir):
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys, subprocess
commandes = [
[ r'Synchroniser D:/SITES vers @UBUNTU64-V'
, r'rsync -a --delete /cygdrive/d/SITES/
pierre@UBUNTU64-V:/home/pierre/SITES/']
, [ r'Synchroniser D:/SITES vers @UBUNTU64-V'
, r'rsync -a --delete /cygdrive/d/SITES/
"pierre@UBUNTU64-V:/home/pierre maurette/SITES/"']
, [ r'Synchroniser D:/SITES vers @UBUNTU64-V'
, r'rsync -a --delete /cygdrive/d/SITES/
"pierre@UBUNTU64-V:/home/pierre/SITES/"']
]
def getShellCommandResult(command=['ls']):
p = subprocess.Popen(args=command
, stdin=subprocess.PIPE
, stdout=subprocess.PIPE
, stderr=subprocess.STDOUT)
pw = p.wait()
return pw, p.stdout.readlines()
basecmd = 'python -c "import sysfor _ in sys.argv[1:]: print _" '
for num, item in enumerate(commandes):
print '%i\t%s' % (num, item[0])
pw, result = getShellCommandResult(basecmd + item[1])
for item in result:
print item.strip()
pw, result = getShellCommandResult(commandes[2][1])
if pw != 0:
print '[!!! error %d]' % pw
if len(result) > 0:
print ''.join(result)
--
Pierre Maurette
Je cherche à réutiliser l'existant concernant l'analyse primaire de la
ligne de commandes, en fait le découpage. J'ai une ligne de commande
sous forme de chaîne de caractères:
r'rsync -a "pierre@UBUNTU64-V:/home/pierre maurette/SITES/"'
et je veux en tirer une liste de chaînes. Le problème évidemment se
situe au niveau des arguments contenant des espaces. C'est encore assez
facile de traiter les '"', mais si on ajoute les échappements et
peut-être d'autres subtilités, ça risque de se compliquer. D'où ma
volonté d'utiliser ce qui existe.
Je n'ai pas trouvé dans Python où est fait ce découpage. En fait, je ne
sais pas si c'est fait par Python ou par l'OS. Pour un exécutable
compilé, c'est l'OS.
Pour l'instant, j'utilise une méthode un peu bourri, je lance une
instance de Python avec la ligne de commandes et je récupère sys.argv.
J4ai survolé optparse (que j'utilise) et getopt (que je n'utilise pas)
mais je n'ai rien vu, il semble que ces modules se situent en aval de
l'analyse primaire.
Y a-t-il une fonction qui me ferait ça simplement ? Je me suis résolu à
poser la question parce que j'ai constaté qu'en Python je passais pas
mal de temps à réinventer la roue, alors qu'il existe beaucoup de
ressources que j'ignore, ou pire que j'ai oublié après les avoir
utilisées une fois grâce à Google.
Pour info mon code de test avec la méthode bourrin (le but de ce petit
outil est de gérer une ruche de commandes chiantes à mémoriser et à
saisir):
#! /usr/bin/env python
# -*- coding: utf-8 -*-
import sys, subprocess
commandes = [
[ r'Synchroniser D:/SITES vers @UBUNTU64-V'
, r'rsync -a --delete /cygdrive/d/SITES/
pierre@UBUNTU64-V:/home/pierre/SITES/']
, [ r'Synchroniser D:/SITES vers @UBUNTU64-V'
, r'rsync -a --delete /cygdrive/d/SITES/
"pierre@UBUNTU64-V:/home/pierre maurette/SITES/"']
, [ r'Synchroniser D:/SITES vers @UBUNTU64-V'
, r'rsync -a --delete /cygdrive/d/SITES/
"pierre@UBUNTU64-V:/home/pierre/SITES/"']
]
def getShellCommandResult(command=['ls']):
p = subprocess.Popen(args=command
, stdin=subprocess.PIPE
, stdout=subprocess.PIPE
, stderr=subprocess.STDOUT)
pw = p.wait()
return pw, p.stdout.readlines()
basecmd = 'python -c "import sysfor _ in sys.argv[1:]: print _" '
for num, item in enumerate(commandes):
print '%i\t%s' % (num, item[0])
pw, result = getShellCommandResult(basecmd + item[1])
for item in result:
print item.strip()
pw, result = getShellCommandResult(commandes[2][1])
if pw != 0:
print '[!!! error %d]' % pw
if len(result) > 0:
print ''.join(result)
--
Pierre Maurette

Poser une question


Pas tout à fait. C'est le shell qui fait le découpage. Le systà ¨me ne
voit que les mots fournis aux variantes de execve().
Ce n'est pas forcément une mauvaise solution. En tout cas elle est
portable.
En C/POSIX il y a wordexp(). Je ne sais pas si c'est visible en python,
ça ne semble pas faire partie de la lib (mais je n'ai pas beaucoup
cherché).
-- Alain.
Oui, en fait en écrivant OS, je pensais au shell. Disons d'une façon
générale le loader, le chargeur, l'interprêteur de commande. Et
maintenant je vois bien que ce n'est pas fondamentalement différent
pour un script Python. C'est l'exécutable python ou python.exe qui
reçoit la première salve dont il retire le premier élément, etc.
La portabilité est une contrainte. Je vais donc pour le moment
continuer avec cette méthode en attendant d'autres propositions
éventuelles.
On doit pouvoir prendre le source de wordexp() peut-être plus clair
qu'un document normatif et en découler une fonction Python, mais le jeu
n'en vaut pas la chandelle pour l'instant.
Merci et bonne journée...
--
Pierre Maurette
Il me semble que tu devrais regarder :
- le module getopt pour la décomposition des divers arguments,
- le module urlparse pour décomposer les sous-parties de l'arguments de
rsync décrivant ton url.
[...]
Merci. Je suis toujours trop verbeux quand je pose une question, je
n'ai pas été clair. J'ai survolé getopt, il me semble bien que ça vient
en aval du découpage primaire. Je jetterai un oeil à urlparse. Mais
rsync n'est qu'un exemple, ce que je veux c'est à partir d'une chaîne
par exemple copiée-collée depuis une console, obtenir le découpage, le
même que celui que fait le shell, pour renvoyer cette liste dans
subprocessPopen(). D'ailleurs ça fonctionne correctement avec mon
bidule bourrin.
Je pourrais bien entendu envoyer la chaîne complète dans os.system() ou
peut-être subprocess.call(), mais ça ne fait pas ce que je veux. Et il
me semble qu'envoyer une chaîne unique dans subprocess.Popen() ne
fonctionne pas, ou pas toujours. Mais je me trompe peut-être à ce
niveau.
--
Pierre Maurette
Désolé, c'est ma fautre : j'avais lu ton premier mail un peu rapidement,
et surtout sans lire l'exemple.
Il m'est arrivé par contre d'utiliser le os.popen() sans trop de
problèmes. Je n'ai pas encore utilisé le module subprocess mais on doit
y retrouver les mêmes fonctionnalités, avec une meilleure portabilité
que os.popen()
Bonne continuation dans tes recherche.