J'ai besoin d'exécuter la commande date | grep -o -w '"+tz+"'' | wc -w
en utilisant Python sur mon hôte local. J'utilise le module subprocess
pour le même et j'utilise le check_output
méthode car j'ai besoin de capturer la sortie pour la même chose.
Cependant, cela me lance une erreur:
Traceback (most recent call last):
File "test.py", line 47, in <module>
check_timezone()
File "test.py", line 40, in check_timezone
count = subprocess.check_output(command)
File "/usr/lib/python2.7/subprocess.py", line 537, in check_output
process = Popen(stdout=PIPE, *popenargs, **kwargs)
File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
errread, errwrite)
File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child
raise child_exception-
OSError: [Errno 2] No such file or directory
S'il vous plaît, aidez-moi où je me trompe. Je suis nouveau sur python
Vous devez ajouter Shell=True
Pour exécuter une commande Shell. check_output
Tente de trouver un exécutable appelé: date | grep -o -w '"+tz+"'' | wc -w
Et il ne le trouve pas. (aucune idée de la raison pour laquelle vous avez supprimé les informations essentielles du message d'erreur).
Voyez la différence entre:
>>> subprocess.check_output('date | grep 1')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python3.4/subprocess.py", line 603, in check_output
with Popen(*popenargs, stdout=PIPE, **kwargs) as process:
File "/usr/lib/python3.4/subprocess.py", line 848, in __init__
restore_signals, start_new_session)
File "/usr/lib/python3.4/subprocess.py", line 1446, in _execute_child
raise child_exception_type(errno_num, err_msg)
FileNotFoundError: [Errno 2] No such file or directory: 'date | grep 1'
Et:
>>> subprocess.check_output('date | grep 1', Shell=True)
b'gio 19 giu 2014, 14.15.35, CEST\n'
Lisez la documentation sur les arguments fréquemment utilisés pour plus d'informations sur l'argument Shell
et comment il modifie l'interprétation des autres arguments.
Notez que vous devez essayer d'éviter d'utiliser Shell=True
Car la génération d'un Shell peut être un danger pour la sécurité (même si vous n'exécutez pas d'attaques d'entrée non fiables comme Shellshock peut toujours être effectuée!).
La documentation du module de sous-processus contient une petite section sur remplacement du pipeline Shell . Vous pouvez le faire en générant les deux processus dans python et utilisez subprocess.PIPE
:
date_proc = subprocess.Popen(['date'], stdout=subprocess.PIPE)
grep_proc = subprocess.check_output(['grep', '1'], stdin=date_proc.stdout, stdout=subprocess.PIPE)
date_proc.stdout.close()
output = grep_proc.communicate()[0]
Vous pouvez écrire une fonction wrapper simple pour définir facilement des pipelines:
import subprocess
from shlex import split
from collections import namedtuple
from functools import reduce
proc_output = namedtuple('proc_output', 'stdout stderr')
def pipeline(starter_command, *commands):
if not commands:
try:
starter_command, *commands = starter_command.split('|')
except AttributeError:
pass
starter_command = _parse(starter_command)
starter = subprocess.Popen(starter_command, stdout=subprocess.PIPE)
last_proc = reduce(_create_pipe, map(_parse, commands), starter)
return proc_output(*last_proc.communicate())
def _create_pipe(previous, command):
proc = subprocess.Popen(command, stdin=previous.stdout, stdout=subprocess.PIPE)
previous.stdout.close()
return proc
def _parse(cmd):
try:
return split(cmd)
except Exception:
return cmd
Avec cela en place, vous pouvez écrire pipeline('date | grep 1')
ou pipeline('date', 'grep 1')
ou pipeline(['date'], ['grep', '1'])
D'après mon expérience, la cause la plus courante de FileNotFound avec un sous-processus est l'utilisation d'espaces dans votre commande. Utilisez plutôt une liste.
# Wrong, even with a valid command string
subprocess.run(["date | grep -o -w '\"+tz+\"' | wc -w"])
# Fixed
subprocess.run(["date", "|", "grep", "-o", "-w", "'\"+tz+\"'", "|", "wc", "-w"])
Cette modification n'entraîne plus d'erreurs FileNotFound et constitue une bonne solution si vous êtes arrivé à la recherche de cette exception avec une commande plus simple. Si vous utilisez python 3.5 ou supérieur, essayez d'utiliser cette approche:
import subprocess
a = subprocess.run(["date"], stdout=subprocess.PIPE)
print(a.stdout.decode('utf-8'))
b = subprocess.run(["grep", "-o", "-w", "'\"+tz+\"'"],
input=a.stdout, stdout=subprocess.PIPE)
print(b.stdout.decode('utf-8'))
c = subprocess.run(["wc", "-w"],
input=b.stdout, stdout=subprocess.PIPE)
print(c.stdout.decode('utf-8'))
Vous devriez voir comment la sortie d'une commande devient l'entrée d'une autre, tout comme l'utilisation d'un tube Shell, mais vous pouvez facilement déboguer chaque étape du processus en python. L'utilisation de subprocess.run est recommandée pour python> 3.5, mais n'est pas disponible dans les versions antérieures.