Alexander Mieller: Finden und Kopieren

Hallo,

habe eine Stunde lang gesucht und keine passende Antwort gefunden. Ich habe in einem Verzeichniss mehrere Unterverzeichnisse mit je mehreren weiteren Unterverzeichnissen. In jedem Verzeichniss liegen verschiedene Dateien, darunter .jpg.

Ich möchte alle Dateien von allen Verzeichnissen finden und in ein anderes Verzeichis kopieren und zwar so, dass die Struktur nach dem Kopieren flach ist.

Quelle:

images/a/b/image-s.jpg
images/a/image-as.jpg
images/a/c/image-xy.jpg

Ziel soll dann so aussehen:

images-new/image-s.jpg
images/image-as.jpg
images/image-xy.jpg

.... eben flach und mit allen *.jpg Dateien von allen Unterverzeichnissen des "images" Pfades.

Ich benötige dazu ein Unix Befehl, den ich über SSH ausführen könnte.
Danke.

Gruß Alexander.

  1. Lieber Alexander,

    meines Wissens reicht dazu ein einzelner Befehl nicht. Dieser Vorgang ist so komplex, dass es dazu eines kleinen Scripts bedarf. Wie man ein Shell-Script schreibt, ist mir aber nicht bekannt. Ich verstehe nur etwas davon, wie ich das in PHP lösen könnte.

    Liebe Grüße,

    Felix Riesterer.

    --
    ie:% br:> fl:| va:) ls:[ fo:) rl:° n4:? de:> ss:| ch:? js:) mo:} zu:)
    1. Hallo Felix,

      meines Wissens reicht dazu ein einzelner Befehl nicht.

      erweitere Dein Wissen.

      Dieser Vorgang ist so komplex, dass es dazu eines kleinen Scripts bedarf.

      Gerade komplexe Vorgänge können oftmals in der Shell mit sehr geringem Schreibaufwand erledigt werden. Allerdings ist hier kein "echtes" Skript erforderlich, da dies eine normale Anwendungsform von find ist.

      Dass die Shell (egal welche) regelmäßig unterschätzt wird, kommt bei $programmierern und interessierten Laien öfter vor, siehe z.B. diesen Archivbeitrag.

      Freundliche Grüße

      Vinzenz

  2. Hallo Alexander,

    Ich möchte alle Dateien von allen Verzeichnissen finden und in ein anderes Verzeichis kopieren und zwar so, dass die Struktur nach dem Kopieren flach ist.

    images/a/b/image-s.jpg
    images/a/image-as.jpg
    images/a/c/image-xy.jpg

    Ziel soll dann so aussehen:

    images-new/image-s.jpg
    images/image-as.jpg
    images/image-xy.jpg

    wohl eher:

    images-new/image-s.jpg
    images-new/image-as.jpg
    images-new/image-xy.jpg

    .... eben flach und mit allen *.jpg Dateien von allen Unterverzeichnissen des "images" Pfades.

    Du hast die Stichworte doch selbst genannt, sie stehen sogar in Deinem Thema:

    Finden:   find
    Kopieren: cp

    Nun noch beides verbinden und gut ist :-)
    Fangen wir damit an:

    1. Schritt: Finde die zu kopierenden Dateien

    find path/to/images -name *.jpg

    Die Standardaktion von find ist, die ermittelte Liste auszugeben. Will man was anderes tun, so nutzt man -exec, gefolgt von dem Kommando, das mit einem Semikolon abzuschließen ist (wobei darauf zu achten ist, dass das Semikolon mit einem Backslash für die Shell maskiert werden muss und davor ein Leerzeichen ist). Auf die einzelnen Fundergebnisse (mit Pfad) wird im Kommando über {} zugegriffen:

    2. Schritt

    find path/to/images -name *.jpg -exec cp {} path/to/images-new/ ;

    und Du hast, was Du suchst: Kopiere mir alle Dateien aus einer bestimmten Verzeichnisstruktur ab einem bestimmten Startverzeichnis in ein Zielverzeichnis, ohne dass dort eine Unterverzeichnisstruktur entsteht.

    Du siehst, wir sind mit Finden (find) und Kopieren (cp) ausgekommen.
    Mehr zu find findest Du in der umfangreichen Manpage von find: man find.

    Bitte beachte, dass bei mehrfach auftretenden Dateinamen, die zuletzt gefundene Datei eine zuvor gefundene mit gleichem Namen überschreibt.

    Freundliche Grüße

    Vinzenz

    1. Hi Vinzenz Mai,

      So habe gerade mal etwas experimentiert. Des Wegen habe ich zwei Anmerkungen zu deinen guten Beitrag.

      (1) Scheint es sinnvoll zu sein find . -name '*.jpg' zu schreiben. Warum, das Suchmuster besser in Hochkommata kommt, ist mir nicht klar.

      (2) Die Verwendung von -exec halte ich für suboptimal. Zum einem mache ich dabei immer schnell Syntax Fehler. Zum anderem wird für jede gefundene Datei ein neuer Prozess erzeugt. Dieses kann durch die Verwendung

      find . -name '*.jpg' -print0 |xargs -0r Kommando

      verhindert werden.

      MfG
      Otto

      1. Heißa, Otto,

        (1) Scheint es sinnvoll zu sein find . -name '*.jpg' zu schreiben. Warum, das Suchmuster besser in Hochkommata kommt, ist mir nicht klar.

        Weil die Shell standardmäßig den Parameter *.jpg auflöst, also durch die Namen aller .jpg-Dateien im aktuellen Verzeichnis ersetzt. Nur wenn es dort keine gibt, wird der String "*.jpg" als Parameter übergeben. Damit dieser String immer so übergeben wird, setzt man ihn in Anführungszeichen.

        Mein Weg wären ja die folgenden beiden Befehle:

          
        IFS="  
        "  
        cp -i $(find images/ -name "*.jpg" -type f) images-new/  
        
        

        (Die Variable IFS legt das Trennzeichen fest, nach dem ein String in ein Array konvertiert wird. Standardmäßig ist sie ein Whitespace jeglicher Art. Ich setze sie hier auf einen Zeilenumbruch, damit nicht aus einem Dateinamen, der ein Leerzeichen enthält, zwei Parameter für den cp-Befehl werden. Den -i-Parameter verwende ich fürs cp, damit ich es bemerke, wenn aus Versehen zwei Dateien den gleichen Namen haben.)

        Gautera!
        Grüße aus Biberach Riss,
        Candid Dauth

        --
        „Soggt da Duaschd zum Hunga:
        ‚I hob heid noh niggs drunga.‘
        Do soggt da Hunga zum Duaschd:
        ‚Woaßt wos? Dehs is mia wuaschd!‘“
        1. Hallo Candid,

          Weil die Shell standardmäßig den Parameter *.jpg auflöst, also durch die Namen aller .jpg-Dateien im aktuellen Verzeichnis ersetzt. Nur wenn es dort keine gibt, wird der String "*.jpg" als Parameter übergeben. Damit dieser String immer so übergeben wird, setzt man ihn in Anführungszeichen.

          danke für die Erinnerung, das müsste ich auch mal gewußt haben. Mir persönlich gefällt Ottos Ansatz am besten, weil mir insbesondere die einfachere Syntax einleuchtet. Dein Vorschlag gefällt mir auch, aber ...

          Mein Weg wären ja die folgenden beiden Befehle:

          ... ein Einzeiler ist schicker als zwei Befehle ;-)

          Freundliche Grüße

          Vinzenz

        2. Hi Candid Dauth,

          Heißa, Otto,

          (1) Scheint es sinnvoll zu sein find . -name '*.jpg' zu schreiben. Warum, das Suchmuster besser in Hochkommata kommt, ist mir nicht klar.

          Weil die Shell standardmäßig den Parameter *.jpg auflöst, also durch die Namen aller .jpg-Dateien im aktuellen Verzeichnis ersetzt. Nur wenn es dort keine gibt, wird der String "*.jpg" als Parameter übergeben. Damit dieser String immer so übergeben wird, setzt man ihn in Anführungszeichen.

          Ja, schon wieder etwas gelernt. Danke.

          MfG
          Otto