Seite 1 von 2 12 LetzteLetzte
Zeige Ergebnis 1 bis 30 von 34
  1. #1
    Chawki
    Gast

    Dateien mit Sonderzeichen im Namen und Skripte ...

    Um auch ausgefallene Dateienamen, beispielsweise mit Leerzeichen, in Skripten zu verarbeiten, benute ich doppelte Anführungsstriche, aber das funktioniert nicht richtig:

    system(cp --sparse=always "./quake3/defrag/demos/runrs_27.440_mati@$$_argentina.dm_66" "./quake3/defrag/demos/dup__X8rwbR9") failed
    system: Invalid argument

    Irgendwelche Vorschläge?


  2. #2
    Houzer&Deif
    Gast
    ja.
    einfache Anführungszeichen. Maskieren sämtliche "Sonderzeichen" für die Shell. Dann funktionieren aber auch Variablen nicht mehr. Nun.. wer's braucht.

    HALLO="Sack"
    echo ${HALLO} --> Sack
    echo "${HALLO} --> Sack
    echo '${HALLO} --> ${HALLO}


    €dit: ups - ich sollte erstmal lesen was du willst ;-)


  3. #3
    Benutzerbild von texray
    Registriert seit
    Jul 2001
    Beiträge
    1.537
    Likes
    0
    Ähm, so wie du das schreibst kann das doch gar nicht gehen oder?
    system(blah), muss das nicht heissen system("blah")?
    Also auch das "cp" mit in die Anführungszeichen? Die Anführungszeichen für die Shell müsstest du dann aus-\-en:
    system("cp \"blub\" \"moep\"");
    [small]"Unterschreiben Sie einfach hier", sagte der Teufel, "und nennen Sie Ihren Wunsch."
    Jonathan Palmer seufzte. "Ich wünsche mir ein Utopia", sagte er. "Eine makellose
    Welt ohne Unrecht und Böses."
    "Aber...", sagte der Teufel und sah überrascht drein, während er für immer verschwand.
    "Scheint alles schon viel besser zu sein", sagte Jonathan Palmer, während er für immer
    verschwand. "Viel, viel besser", sagte seine Frau und wandte sich vom Schlüsselloch
    ab, um ihren Geliebten, Raoul, zu umarmen. Während sie für immer verschwand,
    erinnerte sich Raoul daran, daß er der einzige Begünstigte ihrer immensen Lebens-
    versicherung war. Er verschwand auf der Stelle, gefolgt von dem verschlagenen
    Versicherungsangestellten, dem profitgierigen Versicherungsboß und dem ganzen Rest
    der unperfekten Menschheit. Ich allein bin übrig. Ha ha ...
    [/small]

  4. #4
    palandir
    Gast
    Wenn's um Perl geht (da du von Skripten schreibst), kannst du um die \-Orgien zu vermeiden auch qq// (bzw. q// für Single-Quotes (ohne Variableninterpolation)) benutzen, um einen String einzugrenzen. Für // kann man dabei jede erdenklichen Zeichenpaare benutzen... alles was nicht alphanumerisch und nicht Whitespace ist. Z.B. !!, ||, ## usw... und {}, (), <>, [].
    Für Ruby geht's genau so, nur heißt's dort Q statt qq.

  5. #5
    Benutzerbild von ap0calypse
    Registriert seit
    Jan 2004
    Ort
    Wörgl / Tirol / Austria
    Beiträge
    1.428
    Likes
    0
    Jedenfalls hat texray recht, wenn er sich über die Anführungszeichen wundert:


    SYNOPSIS
    #include <stdlib.h>

    int system(const char *string);


    int ret = system("foo");
    /* EDIT */
    Shit, ich habe das mit "Scripts" wieder mal völlig übersehen

    /* EDIT Nr. 2 */

    Ist Zeitumstellung? Bin ich eine Stunde zu früh aufgestanden? Auf meiner Uhr ist es 5. Das Forum sagt mir, es ist 4 .... Wie spät ists jetzt wirklich? AHH Ich bin verwirrt!
    To follow the path:
    look to the master,
    follow the master,
    walk with the master,
    see through the master,
    become the master.

  6. #6
    Chawki
    Gast
    Aha, danke
    Also vorher hatte ich:

    Code:
      memset (a_cd, 0, BUFSIZ);
      snprintf (a_cd, BUFSIZ - 1, "cp --sparse=always \"%s\" \"%s\"", filea, fileb);
      i = system (a_cd);
      if (i)
      {
        fprintf (stderr, "system(%s) failed\n", a_cd);
        perror ("system");
        return -1;
      }
    und die kritische Zeile habe ich nun durch

    Code:
      snprintf (a_cd, BUFSIZ - 1, "cp --sparse=always \'%s\' \'%s\'", filea, fileb);
    ersetzt.

    Allerdings reicht das bei Dateien mit einfachen Anführungsstrichen im Dateinamen beispielsweise

    quake3/baseq3/tmp/'Gladiators'Pit.pk3

    nicht aus. Was kann man da machen?




  7. #7
    Benutzerbild von Mithrandir
    Registriert seit
    Aug 2000
    Ort
    Aachen
    Beiträge
    3.986
    Likes
    0
    Original erstellt von nobody0
    Allerdings reicht das bei Dateien mit einfachen Anführungsstrichen im Dateinamen beispielsweise

    quake3/baseq3/tmp/'Gladiators'Pit.pk3

    nicht aus. Was kann man da machen?
    Wie wärs wenn du filea und fileb vorher durch ne Funktion jagst, die von links nach rechts alle Zeichen abklappert im String und aus ' ein \' macht?
    [small]Viele Namen habe ich in vielen Ländern. Mithrandir heiße ich bei den Elben, Tharkûn bei den Zwergen;
    Olórin war ich in meiner Jugend im Westen, der vergessen ist, im Süden Incánus, im Norden Gandalf; in den Osten gehe ich nicht.


    J.R.R. Tolkien - The Lord Of The Rings[/small]

  8. #8
    Chawki
    Gast
    Original erstellt von MithrandiR

    Wie wärs wenn du filea und fileb vorher durch ne Funktion jagst, die von links nach rechts alle Zeichen abklappert im String und aus ' ein \' macht?
    Gibt's keine andere Möglichkeit?

    Und bei welchen anderen Zeichen müsste das noch gemacht werden?

  9. #9
    Benutzerbild von texray
    Registriert seit
    Jul 2001
    Beiträge
    1.537
    Likes
    0
    Ich bin mir zwar nicht sicher, was du vorhast, aber ich bin mir fast sicher dass das aus deinem C-Programm umständlicher ist als wenn du ein Bash- oder Perl-Script schreiben würdest (wo sich viel einfacher mit den ganzen "-Geschichten arbeiten lässt).
    [small]"Unterschreiben Sie einfach hier", sagte der Teufel, "und nennen Sie Ihren Wunsch."
    Jonathan Palmer seufzte. "Ich wünsche mir ein Utopia", sagte er. "Eine makellose
    Welt ohne Unrecht und Böses."
    "Aber...", sagte der Teufel und sah überrascht drein, während er für immer verschwand.
    "Scheint alles schon viel besser zu sein", sagte Jonathan Palmer, während er für immer
    verschwand. "Viel, viel besser", sagte seine Frau und wandte sich vom Schlüsselloch
    ab, um ihren Geliebten, Raoul, zu umarmen. Während sie für immer verschwand,
    erinnerte sich Raoul daran, daß er der einzige Begünstigte ihrer immensen Lebens-
    versicherung war. Er verschwand auf der Stelle, gefolgt von dem verschlagenen
    Versicherungsangestellten, dem profitgierigen Versicherungsboß und dem ganzen Rest
    der unperfekten Menschheit. Ich allein bin übrig. Ha ha ...
    [/small]

  10. #10
    palandir
    Gast
    Ist ja doch C...

    [12:07] < illuminate> Um auch ausgefallene Dateienamen, beispielsweise mit Leerzeichen, in Skripten zu verarbeiten, ...
    [12:08] < illuminate> mmkay...


  11. #11
    Chawki
    Gast
    Original erstellt von texray
    Ich bin mir zwar nicht sicher, was du vorhast, aber ich bin mir fast sicher dass das aus deinem C-Programm umständlicher ist als wenn du ein Bash- oder Perl-Script schreiben würdest (wo sich viel einfacher mit den ganzen "-Geschichten arbeiten lässt).
    Wie soll das einfacher sein, wenn weder einfache noch doppelte Anführungsstriche weiterhelfen?


    Original erstellt von ibt.1lluminate
    Ist ja doch C...
    Stimmt nicht ganz, denn system führt ja ein Bash-Skript aus; es ist ein Inline-Skripting.

  12. #12
    Benutzerbild von ap0calypse
    Registriert seit
    Jan 2004
    Ort
    Wörgl / Tirol / Austria
    Beiträge
    1.428
    Likes
    0
    Es ist sogar SICHER einfacher ein Script in Perl (?) oder einfach in der Bash zu tippseln als sich da mit C die wildesten Verrenkungen ausdenken zu müssen.

    Wenn du sagst, WAS du geneu machen willst, könnte dir sicher der eine oder der andere hier helfend zur Hand gehen.
    To follow the path:
    look to the master,
    follow the master,
    walk with the master,
    see through the master,
    become the master.

  13. #13
    Chawki
    Gast
    So, nun habe ich einen String mit dem exakten Dateinamen für lstat, unlink usw. und einen String mit dem expandieren Dateinamen für die Shell.
    Das Expandieren mache ich mit dieser kleinen Funktion:

    Code:
    // expand ' -> \' etc.
    void
    expand_string (char a_c[BUFSIZ], char a_buffer[BUFSIZ])
    {
      int i, j = 0;
    
      // init
      memcpy (a_buffer, a_c, BUFSIZ);       // copy string to buffer
      memset (a_c, 0, BUFSIZ);      // empty string to avoid appending '\0'
      for (i = 0; i < BUFSIZ and (a_buffer[i] not_eq '\0') and j < BUFSIZ; i++)     // expand during copiing buffer to string
      {
          if ((' ' == a_buffer[i]) or ('\'' == a_buffer[i]) or ('<' == a_buffer[i]) or ('>' == a_buffer[i]) //
    	  or ('@' == a_buffer[i]) or ('$' == a_buffer[i]) or ('~' == a_buffer[i]) or ('=' == a_buffer[i]) //
    	  or ('(' == a_buffer[i]) or (')' == a_buffer[i]) or ('{' == a_buffer[i]) or ('}' == a_buffer[i]) //
    	  or ('[' == a_buffer[i]) or (']' == a_buffer[i]) or ('\?' == a_buffer[i]) or ('|' == a_buffer[i]) //
    	  or ('*' == a_buffer[i]) or ('`' == a_buffer[i]) or ('\"' == a_buffer[i]) or ('\\' == a_buffer[i]) //
    	  or ('\a' == a_buffer[i]) or ('\b' == a_buffer[i]) or ('\f' == a_buffer[i]) or ('\n' == a_buffer[i]) //
    	  or ('\r' == a_buffer[i]) or ('\t' == a_buffer[i]) or ('\v' == a_buffer[i]) or (';' == a_buffer[i]))
        {
          a_c[j++] = '\\';
        }
        a_c[j++] = a_buffer[i];
      }
      return;
    }
    Jetzt sollte es auch mit Gemeinheiten wie Vertikaltabulator, Backspace, Wagenrücklauf, Klingelzeichen, Seitenvorschub oder Zeilenende im Dateinmen funktionieren
    Edit: Oben fehlt noch die Abfrage auf '&'.

    @ap0calypse:
    lstat, unlink und pthread_create wären mit Perl wohl kaum machbar.

  14. #14
    edgewalker
    Gast
    Wieso verwendest du überhaupt die Shell, statt das gewünschte Programm direkt aufzurufen?

  15. #15
    Chawki
    Gast
    Wie geht es denn ohne?
    Geht das mit einer der exec-Funktionen?

  16. #16
    Chawki
    Gast
    Also mit

    Code:
      i = execlp ("cp", "--sparse=always", filea, fileb, NULL);
    scheint es nun auch zu funktionieren.

  17. #17
    Benutzerbild von Mithrandir
    Registriert seit
    Aug 2000
    Ort
    Aachen
    Beiträge
    3.986
    Likes
    0
    Das ist ja genau das was deine Shell auch machen soll. Nur muss die Shell erst das kompliziert wieder parsen, was du umständlich kodiert hast. Darüber hinaus sparst du dir auch den Aufwand die Shell zu starten.
    [small]Viele Namen habe ich in vielen Ländern. Mithrandir heiße ich bei den Elben, Tharkûn bei den Zwergen;
    Olórin war ich in meiner Jugend im Westen, der vergessen ist, im Süden Incánus, im Norden Gandalf; in den Osten gehe ich nicht.


    J.R.R. Tolkien - The Lord Of The Rings[/small]

  18. #18
    Chawki
    Gast
    Naja, so ganz kommt das noch nicht hin, denn ohne fork oder Fehler wird danach nicht im Programm weitergemacht, so dass extra geforkt werden muß; meine obige Lösung ist da nicht komplizierter.

  19. #19
    Benutzerbild von Mithrandir
    Registriert seit
    Aug 2000
    Ort
    Aachen
    Beiträge
    3.986
    Likes
    0
    wie wärs mit: (ungetestet und ohne es jemals wirklich benutzt zu haben )

    Code:
    int status=0;
    pid_t pID = fork();
    if (!pID) /*child process*/
        execlp ("cp", "--sparse=always", filea, fileb, NULL);
    else /*parent process - main*/
        wait(&status);
    Damit gewährleistest du, dass immer nur ein Copy-Prozess läuft und überlastest dein System net.

    Komplizierter ist vielleicht dein Code, aber nicht dessen Ausführung. Ne Shell zu starten nimmt nämlich einen fork mehr in Anspruch. (Einen für die Shell zu starten und dann einen um cp zu starten).

    €: wait will noch nen int-pointer haben für den status seh ich gerade.
    [small]Viele Namen habe ich in vielen Ländern. Mithrandir heiße ich bei den Elben, Tharkûn bei den Zwergen;
    Olórin war ich in meiner Jugend im Westen, der vergessen ist, im Süden Incánus, im Norden Gandalf; in den Osten gehe ich nicht.


    J.R.R. Tolkien - The Lord Of The Rings[/small]

  20. #20
    Benutzerbild von ap0calypse
    Registriert seit
    Jan 2004
    Ort
    Wörgl / Tirol / Austria
    Beiträge
    1.428
    Likes
    0
    Original erstellt von nobody0
    @ap0calypse:
    lstat, unlink und pthread_create wären mit Perl wohl kaum machbar.
    Ich wollte auch wissen, WAS du genau machen willst, die Funktion die dein Programm, Script wasauchimmer verfolgt...

    Ob es mit Perl möglich ist, weiß ich nicht.
    To follow the path:
    look to the master,
    follow the master,
    walk with the master,
    see through the master,
    become the master.

  21. #21
    Chawki
    Gast
    Original erstellt von MithrandiR
    wie wärs mit: (ungetestet und ohne es jemals wirklich benutzt zu haben )

    Code:
    int status=0;
    pid_t pID = fork();
    if (!pID) /*child process*/
        execlp ("cp", "--sparse=always", filea, fileb, NULL);
    else /*parent process - main*/
        wait(&status);
    Damit gewährleistest du, dass immer nur ein Copy-Prozess läuft und überlastest dein System net.

    Komplizierter ist vielleicht dein Code, aber nicht dessen Ausführung. Ne Shell zu starten nimmt nämlich einen fork mehr in Anspruch. (Einen für die Shell zu starten und dann einen um cp zu starten).

    €: wait will noch nen int-pointer haben für den status seh ich gerade.
    Ja, ich habe nun:
    Code:
      switch (i_pid = fork ())
      {
        case -1:                   // parent with fork error
          perror ("fork");
          fprintf (stderr, "Fork failed.\n");
          break;
        case 0:                    // child
          i = execl ("/bin/cp", "--sparse=always", filea, fileb, NULL);
          if (i)
          {
            fprintf (stderr, "execlp(cp --sparse=always %s %s) failed, return value %d\n", filea, fileb, i);
            perror ("fork");
          }
          _exit (i);
          break;
        default:                   // parent with no error: do proceed
          break;
      }
      i = waitpid (i_pid, &status, WUNTRACED);      // wait till child terminates
      if (status)
      {
    ...
    aber unabhängig von execl oder execlp funktioniert es nicht: Es wird damit nie sparse kopiert

    Woran liegt das denn; wie kann man das abstellen?

  22. #22
    edgewalker
    Gast
    Original erstellt von nobody0
    lstat, unlink und pthread_create wären mit Perl wohl kaum machbar.
    perldoc -f lstat
    perldoc -f unlink
    perldoc -f fork

    (Wer braucht Threads, wenn man ein vernünftiges fork(2) hat?)

  23. #23
    Benutzerbild von Mithrandir
    Registriert seit
    Aug 2000
    Ort
    Aachen
    Beiträge
    3.986
    Likes
    0
    Funktioniert das sparse denn wenn du cp von Hand aufrufst?
    [small]Viele Namen habe ich in vielen Ländern. Mithrandir heiße ich bei den Elben, Tharkûn bei den Zwergen;
    Olórin war ich in meiner Jugend im Westen, der vergessen ist, im Süden Incánus, im Norden Gandalf; in den Osten gehe ich nicht.


    J.R.R. Tolkien - The Lord Of The Rings[/small]

  24. #24
    Chawki
    Gast
    Original erstellt von edgewalker

    perldoc -f fork

    (Wer braucht Threads, wenn man ein vernünftiges fork(2) hat?)
    fork ist lahmer, verbraucht mehr Resourcen und erfordert aufwendigere Interprozesskommunikation. Für sowas einfaches wie ein Timeout oder paralleles Sortieren ist fork völlig überdimensioniert und zu aufwendig.

    Und wieso funktioniert cp unter exec nicht?

  25. #25
    Chawki
    Gast
    Also mit der zusätzlichen Option "-f" arbeitet cp nun auch mit den exec-Funktionen korrekt.
    Offensichtlich prüft cp ob es in einer Shell läuft oder nicht.

  26. #26
    edgewalker
    Gast
    Wie bitte soll es das prüfen?

    -f bedeutet, es soll die Zieldatei wenn nötig entfernen.

  27. #27
    Chawki
    Gast
    Original erstellt von edgewalker
    Wie bitte soll es das prüfen?

    -f bedeutet, es soll die Zieldatei wenn nötig entfernen.
    Ja, klar, aber ich mußte feststellen:
    - mit system braucht man kein -f
    - mit exec* braucht man -f; sonst wird nicht sparse (d. h. effektiv mit --sparse=never, also dem Gegenteil des angegebenen) kopiert

    Du kannst es ja selber testen.

    Und das entfernen ist irrelevant, weil der Zieldateiname mit mkstemp erzeugt wird und die (leere) Temporär-Datei vorher mit unlink entfernt wird. Deshalb funktioniert es in jedem Fall, aber bei exec* und ohne -f nicht richtig.
    Das sehe ich ja auch an den Rückgabewerten.

  28. #28
    edgewalker
    Gast
    Konstruiere keine hanebüchenen Erklärungen; Occam's Rasiermesser sollte dir sagen dass eine so umständliche Erklärung wie "cp prüft ob es in der Shell läuft" blödsinning und überflüssig ist.

    -f hat damit auch nichts zu tun.

    Du übergibst -f zufällig als ersten Parameter. Tausche die Positionen von -f und --sparse=always in deinem Aufruf und du wirst feststellen dass es wieder nicht funktioniert.

    Jetzt lass das -f ganz weg; übergib stattdessen einen leeren String als ersten Parameter. Du wirst feststellen dass es dann ordnungsgemäss funktioniert.

    Komisch? Siehe Programming by Coincidence.

    Falls du nicht selbst drauf kommst, was du falsch gemacht hast, werde ich dir erst einen Tipp geben und dann die Lösung. Aber eigentlich habe ich dich grade mit der Nase draufgestossen.

  29. #29
    Chawki
    Gast
    Ich habe nach der Dokumentation programmiert:

    > cp --help
    Aufruf: cp [OPTION]... QUELLE ZIEL
    ...

    int execl(const char *path, const char *arg, ...);
    The const char *arg and subsequent ellipses in the execl, execlp, and
    execle functions can be thought of as arg0, arg1, ..., argn.

    Wo ist denn da ein Fehler?

  30. #30
    edgewalker
    Gast
    Denk mal drüber nach, was in argv[0] stehen sollte...

Forumregeln

  • Es ist dir nicht erlaubt, neue Themen zu verfassen.
  • Es ist dir nicht erlaubt, auf Beiträge zu antworten.
  • Es ist dir nicht erlaubt, Anhänge hochzuladen.
  • Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
  •