Ausführung von Systemprogrammen sh: -c: line 0: unexpected EOF while looking for matching `"

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
Benutzeravatar
nieselfriem
User
Beiträge: 135
Registriert: Sonntag 13. Januar 2013, 16:00

Hallo!

Wir haben in einem Perlscript folgenden Befehl zum ausführen gebracht:
[codebox=perl file=Unbenannt.pl]
my $nonce_string = 'curl -k -u user:password -s http://localhost/balancer-manager | sed -n "/href=/s/.*href=\([^>]*\).*/\1/p" | tail -1 | sed -n "s/.*nonce=\(.*\)\"/\1/p"';
system($nonce_string)
[/code]

Da wir nun die Scripte auf pyton umstellen wollen, wollten wir das auch adaptieren. Nunkommt es jedoch zu folgendem Problem in dem testscript

Code: Alles auswählen

import os
nonce_string = 'curl -k -u user:password -s http://localhost/balancer-manager  | sed -n "/href=/s/.*href=\([^>]*\).*/\1/p" | tail -1 | sed -n "s/.*nonce=\(.*\)\"/\1/p"'
os.system(nonce_string)
sh: -c: line 0: unexpected EOF while looking for matching `"'
sh: -c: line 1: syntax error: unexpected end of file
Ich geh davon aus, das es was Escapesequenz des letzten sed Befehls zu tun hat, denn mit bis zum tail -1 geht noch alles klar. Was muss ich ändern?

VG niesel
BlackJack

@nieselfriem: \ haben in Zeichenketten eine besondere Bedeutung. Die solltest Du entweder entsprechend escapen wenn es ein \ sein soll, oder eine ”raw”-Zeichenkettenliteral verwenden, also ein kleines r davor schreiben.

Edit: Was Du da jetzt hast ist:
[codebox=bash file=Unbenannt.bsh]… | sed -n "/href=/s/.*href=\([^>]*\).*//p" | tail -1 | sed -n "s/.*nonce=\(.*\)"//p"[/code]
Was Du haben möchtest ist:
[codebox=bash file=Unbenannt.bsh]… | sed -n "/href=/s/.*href=\([^>]*\).*/\1/p" | tail -1 | sed -n "s/.*nonce=\(.*\)\"/\1/p"[/code]
Es sind nicht nur die Anführungszeichen, auch das \1 macht etwas anderes als gewollt (ein Byte mit dem Wert 1 das als Steuerzeichen in der Shell nicht angezeigt wird). Aber selbst bei den Sachen die wie gewünscht heraus kommen, wie die Klammern, würde ich konsistent escapen.

Warum überhaupt diese ganzen externen Programme für etwas das man auch in Python lösen kann?
Benutzeravatar
nieselfriem
User
Beiträge: 135
Registriert: Sonntag 13. Januar 2013, 16:00

Weil es bisher so gut funktioniert hat und wir es eigentlich nur "schnell" umstellen wollten ;)
Ich habe es nun wie folgt umgeschrieben

Code: Alles auswählen

>>> import os
>>> test1='curl -k -u user:password -s http://localhost/balancer-manager | sed -n "/href=/s/.*href=\([^>]*\).*/\\1/p" | tail -1 | sed -n 
"s/.*nonce=\\(.*\\)\"\/\\1/p"'
print test1
curl -k -u user:password -s http://localhost/balancer-manager | sed -n "/href=/s/.*href=\([^>]*\).*/\1/p" | tail -1 | sed -n "s/.*nonce=\(.*\)"\/\1/p"
>>> os.system(test1)
sh: -c: line 0: unexpected EOF while looking for matching `"'
sh: -c: line 1: syntax error: unexpected end of file
256
Ich habe es also korrigiert und entspricht dem perl Aufruf. Dennoch kommt der gleiche Fehler.
Über welche Alternative sollte ich nachdenken um dies mit Python abzubilden?

VG niesel
Sirius3
User
Beiträge: 18335
Registriert: Sonntag 21. Oktober 2012, 17:20

@nieselfriem: neben der Tatsache, dass das schnell Umschreiben wohl doch nicht so schnell geht, ist die Fehlerbehandlung bei externen Aufrufen immer deutlich komplizierter und mit regulären Ausdrücken zu versuchen HTTP und URLs zu parsen, geht nur durch einen glücklichen Zufall gut.

Ich habe mal das HTML-Parsen als regulären Ausdruck gelassen, weil ohne Zusatzpakete das nur schwer umzusetzen wäre:

Code: Alles auswählen

import urllib2
import contextlib
import re

URL = "http://localhost/balancer-manager"
USERNAME = "user"
PASSWORD = "password"

password_manager = urllib2.HTTPPasswordMgrWithDefaultRealm()
password_manager.add_password(None, URL, USERNAME, PASSWORD)
opener = urllib2.build_opener(urllib2.HTTPBasicAuthHandler(password_manager))

with contextlib.closing(opener.open(URL)) as lines:
    for line in lines:
        mtch = re.search('''href=["'](.*?)["']''', line)
        if mtch:
            last_url = mtch.group(1)
query = urllib2.urlparse.urlsplit(last_url).query
nonce = urllib2.urlparse.parse_qs(query)['nonce']
oder doch:

Code: Alles auswählen

from HTMLParser import HTMLParser
class HRefParser(HTMLParser):
    def __init__(self):
        HTMLParser.__init__(self)
        self.hrefs = []

    def handle_starttag(self, tag, attrs):
        attrs = dict(attrs)
        if 'href' in attrs:
            self.hrefs.append(attrs['href'])

with contextlib.closing(opener.open(URL)) as html:
    hrefs = HRefParser()
    hrefs.feed(html.read())
    last_url = hrefs.hrefs[-1]
Benutzeravatar
pillmuncher
User
Beiträge: 1532
Registriert: Samstag 21. März 2009, 22:59
Wohnort: Pfaffenwinkel

@Sirius3:Wirklich?

Ist deine Datasette fast voll? ;)
In specifications, Murphy's Law supersedes Ohm's.
Antworten