Argumente mit Leerzeichen im Capture-Plugin

Bei Problemen mit der Bedienung von TV-Browser, bitte hier posten.
bwalle
Full Member
Beiträge: 60
Registriert: 03 Sep 2004, 16:30

Argumente mit Leerzeichen im Capture-Plugin

Beitrag von bwalle »

Hi,

ist es möglich, Argumente mit Leerzeichen zu übergeben. Also z.B. wenn ich den Sendungsstring angebe und die Sendung heißt "Eine Sendung", dann ist

argv[1] = "Eine"
argv[2] = "Sendung"

im Programm. Ich hätte aber gerne

argv[1] = "Eine Sendung"

Wenn ich Anführungszeichen verwende, dann werden die Anführungszeichen tatsächlich mit übergeben, nicht wie auf der Shell dazu verwendet, die Leerzeichen zu gruppieren.

Danke.

Gruß,
Bernhard
ds10
Site Admin
Beiträge: 19135
Registriert: 23 Jun 2005, 12:36
Kontaktdaten:

Beitrag von ds10 »

Also bei mir funktioniert es mit den Anführungszeichen, zumindest bei einer Batch-Datei. Du könntest höchstens noch \" anstelle des einfachen Anführungszeichen probieren.
"First they ignore you, then they ridicule you, then they fight you, then you win." - Mahatma Gandhi
Unterstütze die Weiterentwicklung von TV-Browser
bwalle
Full Member
Beiträge: 60
Registriert: 03 Sep 2004, 16:30

Beitrag von bwalle »

ds10 hat geschrieben:Also bei mir funktioniert es mit den Anführungszeichen, zumindest bei einer Batch-Datei. Du könntest höchstens noch " anstelle des einfachen Anführungszeichen probieren.
Keine Änderung. Ich verwende allerdings Linux, nicht Windows. Als Test verwende ich schlicht und einfach

Code: Alles auswählen

#!/bin/sh

echo 1=$1
echo 2=$2
echo 3=$3
echo 4=$4
und schaue mir das Resultat im Dialog an.
ds10
Site Admin
Beiträge: 19135
Registriert: 23 Jun 2005, 12:36
Kontaktdaten:

Beitrag von ds10 »

Mag sein, dass die Shell das so interpretiert, theoretisch sollte es aber korrekt übergeben werden. Wie das dann am Ende wirklich aussieht hängt tatsächlich vom Betriebssystem ab, da das Starten eines Prozesses von Java an das Betriebssystem delegiert wird. Möglicherweise würde ja ein anders Programm das auch anders auffassen.
"First they ignore you, then they ridicule you, then they fight you, then you win." - Mahatma Gandhi
Unterstütze die Weiterentwicklung von TV-Browser
bwalle
Full Member
Beiträge: 60
Registriert: 03 Sep 2004, 16:30

Beitrag von bwalle »

ds10 hat geschrieben:Mag sein, dass die Shell das so interpretiert, theoretisch sollte es aber korrekt übergeben werden. Wie das dann am Ende wirklich aussieht hängt tatsächlich vom Betriebssystem ab, da das Starten eines Prozesses von Java an das Betriebssystem delegiert wird. Möglicherweise würde ja ein anders Programm das auch anders auffassen.
Falsch. Ich habe mir den Code angeschaut.

Code: Alles auswählen

p = Runtime.getRuntime().exec((mData.getProgramPath() + " " + params).split(" "),
        null, new File(path));
Unter Linux wird hierbei keine Shell ausgeführt, sondern execve verwendet. Die
Argumente werden dabei der Reihe nach übergeben. Mit Shell müsste man

Code: Alles auswählen

p = Runtime.getRuntime().exec(new String[]{ "sh", "-c", mData.getProgramPath() +
        " " + params }, null, new File(path));
schreiben. (Gerade ausprobiert, geht.)

Alternativ müsste man den Code erweitern damit der split()-Code die
Anführungszeichen behandelt. Mein Vorschlag (ebenfalls getestet):

Code: Alles auswählen

StringBuilder lastString = null;
ArrayList<String> args = new ArrayList<String>();
args.add(mData.getProgramPath());
for (String part : params.split(" ")) {
  if (part.length() > 0 && part.charAt(0) == '"') {
    if (part.charAt(part.length()-1) == '"')
      args.add(part);
    else {
      lastString = new StringBuilder(part);
      lastString.deleteCharAt(0);
    }
  } else if (lastString != null) {
    lastString.append(' ');
    lastString.append(part);
    if (part.charAt(part.length()-1) == '"') {
      lastString.deleteCharAt(lastString.length() - 1);
      args.add(lastString.toString());
      lastString = null;
    }
  } else {
    args.add(part);
  }
}

p = Runtime.getRuntime().exec(args.toArray(new String[0]), null, new File(path));

Gruß,
Bernhard
bwalle
Full Member
Beiträge: 60
Registriert: 03 Sep 2004, 16:30

Beitrag von bwalle »

ds10 hat geschrieben:
bwalle hat geschrieben:
ds10 hat geschrieben:Mag sein, dass die Shell das so interpretiert, theoretisch sollte es aber korrekt übergeben werden. Wie das dann am Ende wirklich aussieht hängt tatsächlich vom Betriebssystem ab, da das Starten eines Prozesses von Java an das Betriebssystem delegiert wird. Möglicherweise würde ja ein anders Programm das auch anders auffassen.
Falsch. Ich habe mir den Code angeschaut.

Code: Alles auswählen

p = Runtime.getRuntime().exec((mData.getProgramPath() + " " + params).split(" "),
        null, new File(path));
Nix falsch, es ist genau wie ich geschrieben habe, das Ausführen wird an das Betriebssystem delegiert, wenn Linux dann eben execve ausführt, dann ist dass eben so.
Naja, dass execve() verwendet wird, hängt von Java ab, und nicht vom
Betriebssystem. Aber ich halte das auch für das erwartete Verhalten wenn man
die Array-Version verwendet.
ds10 hat geschrieben: Das glaube ich dir auch sofort, dass es so geht (da die Parameter alle zusammen weitergereicht werden), aber ein Spezialfall für Linux werden wir sicher nicht einbauen.
Der "Spezialfall" für Linux würde praktisch auf jedem Desktopsystem außer
Windows funktionieren. ;-)
bwalle hat geschrieben:Alternativ müsste man den Code erweitern damit der split()-Code die
Anführungszeichen behandelt. Mein Vorschlag (ebenfalls getestet):

Code: Alles auswählen

StringBuilder lastString = null;
ArrayList<String> args = new ArrayList<String>();
args.add(mData.getProgramPath());
for (String part : params.split(" ")) {
  if (part.length() > 0 && part.charAt(0) == '"') {
    if (part.charAt(part.length()-1) == '"')
      args.add(part);
    else {
      lastString = new StringBuilder(part);
      lastString.deleteCharAt(0);
    }
  } else if (lastString != null) {
    lastString.append(' ');
    lastString.append(part);
    if (part.charAt(part.length()-1) == '"') {
      lastString.deleteCharAt(lastString.length() - 1);
      args.add(lastString.toString());
      lastString = null;
    }
  } else {
    args.add(part);
  }
}

p = Runtime.getRuntime().exec(args.toArray(new String[0]), null, new File(path));
Ist allerdings unter Windows dann wieder nicht korrekt, dort habe ich nämlich aufgrund von WinTVCap_GUI viele Erfahrungen mit dem richtigen Starten von Programmen gemacht und dort funktioniert es nur mit dem kompletten split richtig.
Wenn dem so ist (keine Ahnung, ich habe kein Windows), dann ist aber die
Array-Version der exec()-Methode kaputt. Wenn Java meint, unter Windows eine
Shell verwenden zu müssen, dann muss es selber das richtige Escaping machen.
Eine zusätzliche Beachtung von Anführungszeichen hat unter Windows Problem
verursacht (welche weiß ich auch nicht mehr, ist schon einige Zeit her, ich
weiß nur noch, dass dann einige Programme damit nicht klar kamen). Man könnte
sonst auch einfach eine andere exec-Methode benutzen, die das Splitten selbst
macht, dann bräuchte man das nicht extra einprogrammieren.
Ihr habt nicht zufällig vergessen, die Anführungszeichen selbst dann zu
entfernen nachdem der Split durchgeführt wurde?

Die normale exec()-Methode zu verwenden, also mit Strings, bringt hier auch
nichts, da die auch nur auf Spaces (und Newlines, Tabs, etc.) matched.

Die sauberste Methode wäre m.E. keinen großen String zur Übergabe der
Argumente zu verwenden sondern eine Liste. Dann kann der Anwender schon nach
1., 2., 3., usw. Argument trennen und man braucht kein Escaping verwenden.
Dazu noch jeweils eine Checkbox, ob ein leerer String übergeben werden soll,
wenn das ganze zu einem leeren String evaluiert, oder ob dann die Liste
um eins verschoben werden soll.

Aber dein Text klingt für mich jetzt als ob es nur wichtig wäre, dass es unter
Windows funktioniert. :-/
ds10
Site Admin
Beiträge: 19135
Registriert: 23 Jun 2005, 12:36
Kontaktdaten:

Beitrag von ds10 »

bwalle hat geschrieben:Ihr habt nicht zufällig vergessen, die Anführungszeichen selbst dann zu
entfernen nachdem der Split durchgeführt wurde?
Nicht ihr, wenn dann ich (WinTVCap_GUI habe ich allein geschrieben, wenn also hier einer keine Ahnung hat, dann bin ich das), aber wie ich ja sagte, weiß ich nicht mehr, wo das Problem war, da ich mir wirklich nicht jede Kleinigkeit merken kann.
bwalle hat geschrieben:Die sauberste Methode wäre m.E. keinen großen String zur Übergabe der
Argumente zu verwenden sondern eine Liste. Dann kann der Anwender schon nach
1., 2., 3., usw. Argument trennen und man braucht kein Escaping verwenden.
Dazu noch jeweils eine Checkbox, ob ein leerer String übergeben werden soll,
wenn das ganze zu einem leeren String evaluiert, oder ob dann die Liste
um eins verschoben werden soll.
Da stimme ich dir zu, nur ist das für einen Durchschnittsuser viel zu kompliziert, selbst mit dem jetzigen System haben schon genug Leute Schwierigkeiten.
bwalle hat geschrieben:Aber dein Text klingt für mich jetzt als ob es nur wichtig wäre, dass es unter
Windows funktioniert. :-/
Nein, ich fände es auch gut, wenn es unter Linux problemlos laufen würde. Aber wenn ich allein die Wahl hätte, wäre es mir tatsächlich wichtiger, dass es unter Windows richtig funktioniert, aus rein supporttechnischen Gründen:
https://sourceforge.net/project/showfil ... _id=495879

Linux Benutzer kennen sich im Allgemeinen viel besser mit ihrem System aus und sind daher eher in der Lage mit solchen Problemen umzugehen.
"First they ignore you, then they ridicule you, then they fight you, then you win." - Mahatma Gandhi
Unterstütze die Weiterentwicklung von TV-Browser
bwalle
Full Member
Beiträge: 60
Registriert: 03 Sep 2004, 16:30

Beitrag von bwalle »

ds10 hat geschrieben:
bwalle hat geschrieben:Die sauberste Methode wäre m.E. keinen großen String zur Übergabe der
Argumente zu verwenden sondern eine Liste. Dann kann der Anwender schon nach
1., 2., 3., usw. Argument trennen und man braucht kein Escaping verwenden.
Dazu noch jeweils eine Checkbox, ob ein leerer String übergeben werden soll,
wenn das ganze zu einem leeren String evaluiert, oder ob dann die Liste
um eins verschoben werden soll.
Da stimme ich dir zu, nur ist das für einen Durchschnittsuser viel zu kompliziert, selbst mit dem jetzigen System haben schob genug Leute Schwierigkeiten.
Ehrlich gesagt finde ich das jetzige System für den Durchschnittsuser
komplizierter, da der an bestimmten Stellen Anführungszeichen setzen muss.
bwalle hat geschrieben:Aber dein Text klingt für mich jetzt als ob es nur wichtig wäre, dass es unter
Windows funktioniert. :-/
Nein, ich fände es auch gut, wenn es unter Linux problemlos laufen würde. Aber wenn ich allein die Wahl hätte, wäre es mir tatsächlich wichtiger, dass es unter Windows richtig funktioniert, aus rein supporttechnischen Gründen:
https://sourceforge.net/project/showfil ... _id=495879
Das zählt bei mir als Argument nicht. Ich sag ja nicht dass du die
Windows-Version kaputt machen sollst sondern die Linuxversion fixen.
Ich bin mir auch ziemlich sicher dass MacOS X das gleiche Problem hat.
Linux Benutzer kennen sich im Allgemeinen viel besser mit ihrem System aus und sind daher eher in der Lage mit solchen Problemen umzugehen.

Es gibt keine Möglichkeit, mit dem Problem umzugehen, außer keine Leerzeichen
zu verwenden, was bei Titeln nicht unbedingt die schönste Lösung ist.
Linuxprogramme verwenden i.d.R. getopt() oder getopt_long() zum Parsen
von Argumenten. Diese Funktion geht davon aus, dass die Argumente richtig
sind. Die richtige Übergabe ist Aufgabe der Shell.
ds10
Site Admin
Beiträge: 19135
Registriert: 23 Jun 2005, 12:36
Kontaktdaten:

Beitrag von ds10 »

bwalle hat geschrieben:Es gibt keine Möglichkeit, mit dem Problem umzugehen, außer keine Leerzeichen
zu verwenden, was bei Titeln nicht unbedingt die schönste Lösung ist.
Also das Argument lasse ich jetzt nicht gelten. Du kannst ja sogar programmieren, also wäre es für dich ein leichtest ein Plugin zu basteln, was richtig funktioniert. ;-)

(Das CapturePlugin bietet ja auch noch die Möglichkeit die clean-Funktion zu verwenden um alle Sonderzeichen aus dem übergebenen String zu entfernen, Leerzeichen werden dann zum Unterstrich.)

Das CapturePlugin müsste an der Stelle sowieso mal auf ProcessBuilder umgestellt werden, da das ja jetzt die empfohlene Startweise für externe Prozesse ist.
"First they ignore you, then they ridicule you, then they fight you, then you win." - Mahatma Gandhi
Unterstütze die Weiterentwicklung von TV-Browser
ds10
Site Admin
Beiträge: 19135
Registriert: 23 Jun 2005, 12:36
Kontaktdaten:

Beitrag von ds10 »

Das Problem ist mir jetzt übrigens doch wieder eingefallen. Das Aufnahmeprogramm WinTVCap.exe erwartet alle Kommandos einer Kommandozeile als einzelne Tokens, wenn man dort einen Teil der Kommandos als Ganzes übergibt (also so wie in deinem Codeabschnitt mit sh), funktioniert die Aufnahme nicht. Das ließ sich nur durch das split beheben, alle anderen Programme hatten danach keine Probleme mit Anführungszeichen zusammengesetzte Tokens als solche zu erkennen. Unter Windows muss die Methode also irgendwie anders funktionieren.
"First they ignore you, then they ridicule you, then they fight you, then you win." - Mahatma Gandhi
Unterstütze die Weiterentwicklung von TV-Browser
bwalle
Full Member
Beiträge: 60
Registriert: 03 Sep 2004, 16:30

Beitrag von bwalle »

ds10 hat geschrieben:
bwalle hat geschrieben:Es gibt keine Möglichkeit, mit dem Problem umzugehen, außer keine Leerzeichen
zu verwenden, was bei Titeln nicht unbedingt die schönste Lösung ist.
Also das Argument lasse ich jetzt nicht gelten. Du kannst ja sogar programmieren, also wäre es für dich ein leichtest ein Plugin zu basteln, was richtig funktioniert. ;-)
Klar kann ich die Quellen verändern (oder kopieren umbenennen, und dann
verändern). Das verstehe ich aber
nicht unter "umgehen", sondern "patchen".
(Das CapturePlugin bietet ja auch noch die Möglichkeit die clean-Funktion zu
verwenden um alle Sonderzeichen aus dem übergebenen String zu entfernen,
Leerzeichen werden dann zum Unterstrich.)
Richtig, und das mache ich zur Zeit. Das verstehe ich allerdings unter "keine
Leerzeichen verwenden".
Das CapturePlugin müsste an der Stelle sowieso mal auf ProcessBuilder
umgestellt werden, da das ja jetzt die empfohlene Startweise für externe
Prozesse ist.
Ändert hier nichts am Verhalten. Nur dass es keine Version mehr gibt, die nur
aus einem String besteht.
bwalle
Full Member
Beiträge: 60
Registriert: 03 Sep 2004, 16:30

Beitrag von bwalle »

ds10 hat geschrieben:Das Problem ist mir jetzt übrigens doch wieder eingefallen. Das Aufnahmeprogramm WinTVCap.exe erwartet alle Kommandos einer Kommandozeile als einzelne Tokens, wenn man dort einen Teil der Kommandos als Ganzes übergibt (also so wie in deinem Codeabschnitt mit sh), funktioniert die Aufnahme nicht. Das ließ sich nur durch das split beheben, alle anderen Programme hatten danach keine Probleme mit Anführungszeichen zusammengesetzte Tokens als solche zu erkennen. Unter Windows muss die Methode also irgendwie anders funktionieren.
Ja. Ich hab jetzt mal Windows ausgekramt. Folgender Code

Code: Alles auswählen

Process p = Runtime.getRuntime().exec(
                                new String[]{ "show_args",
                                        ""1", "2"" } );
liefert unter Windows:

Code: Alles auswählen

argv[1] = 1 2
und unter Linux

Code: Alles auswählen

argv[1] = "1
argv[2] = 2"
Also wenn du mich fragst ist das ein Bug von Java unter Windows. Unter Linux bekommt das aufgerufene Programm exakt die Strings, die man ihm von Java übergibt. Unter Windows wird eine Shell aufgerufen und die Anführungszeichen werden weggestrippt.

Allerdings funktioniert das ganze mit

Code: Alles auswählen

Process p = Runtime.getRuntime().exec(
                                new String[]{ "show_args",
                                        "1 mit vielen Leerzeichen", "2" } );
auch unter Windows korrekt. Damit kann dann WinTVCap.exe nicht umgehen, wenn ich dich richtig verstanden habe.
bwalle
Full Member
Beiträge: 60
Registriert: 03 Sep 2004, 16:30

Beitrag von bwalle »

Außerdem habe ich festgestellt dass sich

Code: Alles auswählen

String[]{ "\"1 mit Leerzeichen", "2\"" }
unter Windows nicht ausführen lässt, also eine Exception wirft. IMO ein weiterer Bug (von Java).
ds10
Site Admin
Beiträge: 19135
Registriert: 23 Jun 2005, 12:36
Kontaktdaten:

Beitrag von ds10 »

bwalle hat geschrieben:Ja. Ich hab jetzt mal Windows ausgekramt. Folgender Code

Code: Alles auswählen

Process p = Runtime.getRuntime().exec(
                                new String[]{ "show_args",
                                        ""1", "2"" } );
liefert unter Windows:

Code: Alles auswählen

argv[1] = 1 2
und unter Linux

Code: Alles auswählen

argv[1] = "1
argv[2] = 2"
Also wenn du mich fragst ist das ein Bug von Java unter Windows. Unter Linux bekommt das aufgerufene Programm exakt die Strings, die man ihm von Java übergibt. Unter Windows wird eine Shell aufgerufen und die Anführungszeichen werden weggestrippt.
Ja, kann gut sein, dass dies ein Bug in Java ist.
bwalle hat geschrieben:Allerdings funktioniert das ganze mit

Code: Alles auswählen

Process p = Runtime.getRuntime().exec(
                                new String[]{ "show_args",
                                        "1 mit vielen Leerzeichen", "2" } );
auch unter Windows korrekt. Damit kann dann WinTVCap.exe nicht umgehen, wenn ich dich richtig verstanden habe.
Genau, der Eintrag mit den vielen Leerzeichen würde alle Programme, die die Tokens einzeln erwarten aus dem Tritt bringen.

Es ist auf jeden Fall ziemlich unerwartet, dass sich ein und dieselbe Methode auf den unterschiedlichen BS komplett anders verhält.
"First they ignore you, then they ridicule you, then they fight you, then you win." - Mahatma Gandhi
Unterstütze die Weiterentwicklung von TV-Browser
bwalle
Full Member
Beiträge: 60
Registriert: 03 Sep 2004, 16:30

Beitrag von bwalle »

ds10 hat geschrieben: auch unter Windows korrekt. Damit kann dann WinTVCap.exe nicht umgehen, wenn ich dich richtig verstanden habe.
Genau, der Eintrag mit den vielen Leerzeichen würde alle Programme, die die Tokens einzeln erwarten aus dem Tritt bringen.
Und welche Programme sind das? Vor allem verstehe ich den Sinn immer noch nicht. Erwartet deine Anwendung quasi

Code: Alles auswählen

argv[1] = ein
argv[2] = ganz
argv[3] = langer
argv[4] = String
oder

Code: Alles auswählen

argv[1] = "ein
argv[2] = ganz
argv[3] = langer
argv[4] = String"
Im ersteren Fall braucht man doch nur die Anführungszeichen ganz wegzulassen. Im zweiteren Fall: Wie würde man dann die Anwendung von der Shell (cmd.exe) aufrufen damit das so übergeben wird?
Antworten