Anzeige:
Ergebnis 1 bis 14 von 14

Thema: [C++] Dateiname mit Leerzeichen ausgeben

  1. #1
    Registrierter Benutzer
    Registriert seit
    21.07.2006
    Beiträge
    46

    [C++] Dateiname mit Leerzeichen ausgeben

    Ich möchte in einem C++-Programm Dateinamen mit Leerzeichen auf die Konsole ausgeben und diese Ausgabe mit anderen Programmen weiterverwenden können, z.B. so:
    Code:
    $ ls `meinprogramm`
    Im Programm ist der Dateiname als const char* vorhanden, ein Minimalbeispiel wäre folgendes:
    Code:
    #include <iostream>
    
    int main()
    {
      const char* file = "a b";
      std::cout << file << std::endl;
    }
    Die Ausgabe dieses Programmes wird nicht als die Datei "a b" interpretiert, sondern als die 2 Dateien "a" und "b". Wie kann ich das ändern?

  2. #2
    Registrierter Benutzer Avatar von ContainerDriver
    Registriert seit
    10.01.2003
    Beiträge
    418
    Hallo.

    Du könntest dein Programm mit
    Code:
    $ ls "`meinprogramm`"
    aufrufen.

    Gruß, Florian
    Geändert von ContainerDriver (09-05-2008 um 20:45 Uhr)
    Ein gebrechlich Wesen ist der X-Server.

  3. #3
    Registrierter Benutzer
    Registriert seit
    21.07.2006
    Beiträge
    46
    Zitat Zitat von ContainerDriver Beitrag anzeigen
    Hallo.

    Du könntest dein Programm mit
    Code:
    $ ls "`meinprogramm`"
    aufrufen.

    Gruß, Florian
    Das würde nur bei einer Datei funktionieren; ich hab es vllt vergessen zu erwähnen, dass das Programm beliebig viele Dateinamen ausgeben können soll.

  4. #4
    Registrierter Benutzer Avatar von ContainerDriver
    Registriert seit
    10.01.2003
    Beiträge
    418
    Okay, dann musst du die Leerzeichen (+ eventuell andere von der Shell interpretierte Sonderzeichen, bin mir da aber im Moment nicht so sicher) maskieren und dem gesamten Befehlsaufruf ein eval voranstellen, also so:
    Code:
    #include <iostream>
    
    int main()
    {
      const char* file = "a\\\ b";
      /* 
      Maskierung von \ mit \
      Maskierung von   (Space) mit \
      "doppelte" Maskierung nötig wegen eval-Aufruf
      */
      std::cout << file << std::endl;
    }
    Code:
    $ eval "ls `./prog`"
    . Man könnte statt der maskierten Leerzeichen auch um die einzelne Dateien Anführungszeichen ausgeben (diese müssen wiederum maskiert werden), ist denke ich einfacher umzusetzen, weil im String nicht rumgepfuscht werden muss:
    Code:
      [...]
      std::cout << "\\\\\\\"" << file << "\\\\\\\"" << std::endl;
      //Maskierung von \ in C++ nötig: aus \\\" wird \\\\\\\"
      //eval "ls `./prog`" => eval "ls \"Datei 1\" \"Datei 2\"" 
      [...]
    . Ich hoffe zumindest, dass das geht

    Gruß, Florian
    Ein gebrechlich Wesen ist der X-Server.

  5. #5
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Oder du gibst sie zeilenweise aus und lässt xargs daraus eine Kommmandozeilen bauen

    Quasi

    ./prog | xargs ls

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  6. #6
    Registrierter Benutzer
    Registriert seit
    21.07.2006
    Beiträge
    46
    Zitat Zitat von ContainerDriver Beitrag anzeigen
    Man könnte statt der maskierten Leerzeichen auch um die einzelne Dateien Anführungszeichen ausgeben (diese müssen wiederum maskiert werden), ist denke ich einfacher umzusetzen, weil im String nicht rumgepfuscht werden muss:
    Code:
      [...]
      std::cout << "\\\\\\\"" << file << "\\\\\\\"" << std::endl;
      //Maskierung von \ in C++ nötig: aus \\\" wird \\\\\\\"
      //eval "ls `./prog`" => eval "ls \"Datei 1\" \"Datei 2\"" 
      [...]
    . Ich hoffe zumindest, dass das geht

    Gruß, Florian
    Nachdem ich jetzt ein bisschen mit eval herumgespielt habe, hat bei mir das funktioniert:
    Code:
    std::cout << "\"" << file << "\" ";
    // eval "ls `./prog`" => eval "ls "datei 1" "datei2""
    Mit dem selben C++-Code geht auch
    Code:
    ./prog | xargs ls
    In der xargs Manpage steht übrigens ein interessanter Absatz:
    Because Unix filenames can contain blanks and newlines, this default behavvv&#118;‐
    iour is often problematic; filenames containing blanks and/or newlines are
    incorrectly processed by xargs. In these situations it is better to use the
    -0 option, which prevents such problems. When using this option you will
    need to ensure that the program which produces the input for xargs also uses
    a null character as a separator.
    Danke für eure Lösungsvorschläge bisher, ich bin noch am überlegen, welcher am komfortabelsten ist, und bin natürlich für weitere Ideen offen..

  7. #7
    Administrator Avatar von anda_skoa
    Registriert seit
    17.11.2001
    Ort
    Graz, Österreich
    Beiträge
    5.477
    Ein Vorteil von xargs, je nach erwartetem Output deines Programms, ist, dass es die maximale Länge eine Kommandozeile berücksichtig, d.h. wenn der Output zu viel wird, ruft xargs das nachgestellte Programm mehrmals mit einer ausreichend kurzen Zeile auf.

    Ciao,
    _
    Qt/KDE Entwickler
    Debian Benutzer

  8. #8
    Registrierter Benutzer Avatar von panzi
    Registriert seit
    04.05.2001
    Ort
    Kottingbrunn
    Beiträge
    609
    ...blanks and/or newlines are incorrectly processed by xargs....
    Damit sollten leerzeichen gehn (aber newlines gehn immer noch net):
    Code:
    ./prog | while read fname; do ls "$fname"; done
    Intel Core 2 Duo CPU 2.66GHz; Nvidia GeForce 8 8800 GTS; 4GB RAM; Fedora 12; KDE-testing

  9. #9
    Registrierter Benutzer
    Registriert seit
    21.07.2006
    Beiträge
    46
    Zitat Zitat von panzi Beitrag anzeigen
    Damit sollten leerzeichen gehn (aber newlines gehn immer noch net):
    Code:
    ./prog | while read fname; do ls "$fname"; done
    An so eine Lösung hab ich auch schon gedacht, es hat aber den Nachteil, dass immer einiges getippt werden muss..

    Inzwischen ist mir eine ganz andere Möglichkeit eingefallen:
    Aufruf:
    Code:
    ./prog -c "ls -l"
    C++-code:
    Code:
    // parse die -c - Option
    // erstelle einen String mit dem Befehl aus der Kommandozeile
    // und den Dateinamen mit \" links und rechts davon
    system(commandline);
    Das hat bei mir alle Tests bestanden, also denke ich bei diesem Ansatz zu bleiben.

  10. #10
    Registrierter Benutzer Avatar von panzi
    Registriert seit
    04.05.2001
    Ort
    Kottingbrunn
    Beiträge
    609
    Zitat Zitat von totycro Beitrag anzeigen
    An so eine Lösung hab ich auch schon gedacht, es hat aber den Nachteil, dass immer einiges getippt werden muss..

    Inzwischen ist mir eine ganz andere Möglichkeit eingefallen:
    Aufruf:
    Code:
    ./prog -c "ls -l"
    C++-code:
    Code:
    // parse die -c - Option
    // erstelle einen String mit dem Befehl aus der Kommandozeile
    // und den Dateinamen mit \" links und rechts davon
    system(commandline);
    Das hat bei mir alle Tests bestanden, also denke ich bei diesem Ansatz zu bleiben.
    Das hat aber ganz ähnliche Schwächen wie das mit read und xargs. Also was wenn ein Datename eines der folgenden Zeichen beinhaltet? " ' \

    In hochsprachen wie Python, Rupy, Java etc. aber auchin libraries wie Qt gibts entsprechende Funktionen mit denen man so etwas "sicher" machen kann. Also so auf die art: callprog((const char*[]){"ls","-lh",NULL})
    Intel Core 2 Duo CPU 2.66GHz; Nvidia GeForce 8 8800 GTS; 4GB RAM; Fedora 12; KDE-testing

  11. #11
    Registrierter Benutzer
    Registriert seit
    21.07.2006
    Beiträge
    46
    Zitat Zitat von panzi Beitrag anzeigen
    Das hat aber ganz ähnliche Schwächen wie das mit read und xargs. Also was wenn ein Datename eines der folgenden Zeichen beinhaltet? " ' \

    In hochsprachen wie Python, Rupy, Java etc. aber auchin libraries wie Qt gibts entsprechende Funktionen mit denen man so etwas "sicher" machen kann. Also so auf die art: callprog((const char*[]){"ls","-lh",NULL})
    Sind diese 3 Zeichen (" ' \) die einzigen, bei denen es nicht funktioniert? Die könnte man doch einfach escapen..

  12. #12
    Registrierter Benutzer Avatar von panzi
    Registriert seit
    04.05.2001
    Ort
    Kottingbrunn
    Beiträge
    609
    Zitat Zitat von totycro Beitrag anzeigen
    Sind diese 3 Zeichen (" ' \) die einzigen, bei denen es nicht funktioniert? Die könnte man doch einfach escapen..
    je nach dem ob du ' oder " für die quotes verwendest gibts noch mit mehr ziechen probleme. bei ' gibts nur mit anderen ' probleme. also dann kann mans so machen (ungetesteter c++ code):
    Code:
    #include <iostream>
    
    int system(const std::string & prog, const std::list<std::string> & args) {
       std::stringstream ss;
    
       escape(prog, ss);
       
       for (std::list<std::string>::const_iterator it = args.begin(), end = args.end(); it != end; ++ it) {
          ss << " ";
          escape(*it, ss);
       }
    
       return system(ss.str().c_str());
    }
    
    void escape(const std::string & s, std::ostream & os) {
       os << "'";
       for (std::string::const_iterator it = s.begin(), end = s.end(); it != end; ++ it) {
          if (*it == '\'') {
             os << "'\\''";
          }
          else {
             os << *it;
          }
       }
       os << "'";
    }
    Hab aber schon länger nix mehr mit C++ gemacht. In python:
    Code:
    import os
    
    def system(prog,*args):
       return os.system('%s %s' % (escape(prog),' '.join(escape(arg) for arg in args)))
    
    def escape(s):
       return "'%s'" % s.replace("'","'\\''")
    Intel Core 2 Duo CPU 2.66GHz; Nvidia GeForce 8 8800 GTS; 4GB RAM; Fedora 12; KDE-testing

  13. #13
    Registrierter Benutzer
    Registriert seit
    07.05.2007
    Beiträge
    656
    Moin,

    Zitat Zitat von anda_skoa Beitrag anzeigen
    Oder du gibst sie zeilenweise aus und lässt xargs daraus eine Kommmandozeilen bauen
    oder Du gibst sie im Programm durch \0 getrennt aus und nutzt die -0-Option von xargs. Noch besser: Du machst das per Kommandozeilenoption umschaltbar. So arbeitet der find auch (Option -print0).

    Jan

  14. #14
    Registrierter Benutzer
    Registriert seit
    21.07.2006
    Beiträge
    46
    Das mit dem Schalter ist eine gute Idee, dann kann ich ja einfach alle genannten Methoden implementieren.

    Danke für eure Hilfe!

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •