Bestimmte Dateien kopieren



  • Tag Tag,

    ich möchte ein Skript / Shell-Befehl schreiben, welcher aus einem Ordner (inkl. aller Unterordner) nur die *.c und die *.h Dateien kopiert und unter Beibehaltung der Ordnerstruktur in einem beliebigen Ordner ablegt. Hab schon alle möglichen Konstellationen von find und cp ausprobiert, war für mich leider nicht machbar. Kann mir da jemand helfen?

    Danke Euch!

    Gruß



  • ungetestet

    FILES="`find . -name '*.[c|h]'`"
    
    for i in $FILES; do
      DIR=`dirname $i`
      mkdir -p "$DIR"
      cp "$i" "$DIR"
    done
    


  • so ist besser:

    find . -name '*.[c|h]' | while read i; do
    ...
    done
    


  • Danke erstmal, werds gleich ausprobieren 🙂



  • normal und ohne große Umstände geht das so:

    cd $SRCDIR; find . -name "*.[hc]" -print | cpio -pdvm $DSTDIR

    P.S.: Grad kein Unix/Linux-System zur Hand, aber ich glaube, "*.[hc]" ist korrekt.



  • Hallo beisammen,

    vielen Dank nochmal für die Antworten. Leider funktioniert das nicht so ganz. Hab mir das Skript von kingruedi und DrGreenthumb angeschaut: Es erscheint eine Fehlermeldung beim Kopiervorgang:

    cp: „./abc/xyz/asd.c“ und „./abc/xyz/asd.c“ sind die gleiche Datei

    Ich hätte gerne die gesuchten C- und H-Dateien in der gleichen Ordnerstruktur, aber z.B. in einem Ordner "result", so dass der Kopierbefehl so lauten müsste:

    cp ./abc/xyz/asd.c ./result/abc/xyz/asd.c

    Ist das möglich?

    Vielen Dank 🙂



  • luutsch schrieb:

    Ich hätte gerne die gesuchten C- und H-Dateien in der gleichen Ordnerstruktur, aber z.B. in einem Ordner "result", so dass der Kopierbefehl so lauten müsste:

    cp ./abc/xyz/asd.c ./result/abc/xyz/asd.c

    Ist das möglich?

    Genau das ist das Spezialgebiet von cpio (andere Lösungen machen m.E. nur bei wirklichen Spezialanforderungen überhaupt Sinn; das, was Du vorhast, geht auf jedenfall am einfachsten mit cpio):

    find abc -name "*.[hc]" -print | cpio -pdvm ./result
    

    An Stelle von "abc" kannst Du auch eine Liste aller zu kopierenden Subdirectories angeben, z.B. "find abc bcd efg -name ...". Nur die Zieldirectory selbst als Quelle macht keinen Sinn.

    Bei Bedarf kann bei cpio noch folgende Optionen benutzt/zugefügt werden:
    -u unconditional, z.B. beim Wiederholen zum erneuten unbedingten Kopieren
    -m mit/ohne Beibehaltung der "Modification"-Time
    Die Option "-l" sollte man auf keinen Fall benutzt werden, obwohl in vielen Beispielen gezeigt, sie legt nämlich nur links an.

    Tipp: Führe erst einmal das "find"-Kommando aus. Auch da gibt es diverse Optionen. Alles, was das "find"-Kommando ausgibt, wird als Dateiliste zum Kopieren für das folgende "cpio"-Kommando genommen. Ggf. kannst Du nach dem "find" auch noch filtern, es geht z.B. auch so:

    find abc bcd efg -print | egrep "[hc]$" | cpio -pdvm ./result
    


  • jox schrieb:

    find abc -name "*.[hc]" -print | cpio -pdvm ./result
    

    Schau Dir mal den -exec-Parameter von find an, das -print und die Pipe sind unnötig.

    Und das mit dem Grep am Ende Deines Posts will ich übersehen haben. 😉

    Btw, der Fehler in kingruedis Codeschnipsel ist leicht zu finden, bleibt als Übungsaufgabe dem interessiertne Leser überlassen, auch wenn natürlich trotzdem cpio eine feine Sache bleibt.



  • nman schrieb:

    Schau Dir mal den -exec-Parameter von find an, das -print und die Pipe sind unnötig.

    ... unnötig vielleicht im Zusammenhang damit, wenn man -exec benutzt.

    Sonst:
    (1) -print ist auf einigen Unix-Systemen zwingend notwendig, wenn man eine Ausgabe haben will.
    (2) Die pipe ist notwendig, wenn man den Ausgabestream mit cpio nutzen will.

    P.S.: ... und die -exec Option ist für den ungeübten Nutzer/Anfänger nun wirklich nicht ganz einfach zu verstehen. Das Ding erkläre ich Anfängern immer erst dann, wenn sie das find-Kommando grundsätzlich verstanden haben, sonst schreckt dir kryptische Schreibweise nur ab 😉

    P.P.S.: Was ist gegen einen Filter mit "grep" einzuwenden (als Beispiel). Das ist zumindest für jeden leicht zu durchschauen.

    Edit:
    P.P.P.S.: ... und wenn ich auch noch mal rummeckern darf (machen andere ja auch immer): das Beispiel von @kingruedi mit FILES="`find . -name '*.[c|h]'`" kann arge Probleme machen, wenn die Ergebnisliste zu lang wird (Länge von Shell-Variablen ist begrenzt und hat systembedingt unterschiedliche Obergrenzen).



  • jox schrieb:

    ... unnötig vielleicht im Zusammenhang damit, wenn man -exec benutzt.

    Und genau das sollte man tun.

    P.S.: ... und die -exec Option ist für den ungeübten Nutzer/Anfänger nun wirklich nicht ganz einfach zu verstehen. Das Ding erkläre ich Anfängern immer erst dann, wenn sie das find-Kommando grundsätzlich verstanden haben, sonst schreckt dir kryptische Schreibweise nur ab 😉

    Naja, find hat ohnehin schon ein mieses Interface, insofern ist der Mehraufwand für -exec vernachlässigbar. Außerdem ist die exec-Syntax so seltsam, dass man sie sich möglichst früh antrainieren sollte, sonst vergisst man sie garantiert. 🙂

    Was ist gegen einen Filter mit "grep" einzuwenden (als Beispiel). Das ist zumindest für jeden leicht zu durchschauen.

    cpio kann mit Leer- und Sonderzeichen im Dateinamen recht gut umgehen, aber wenn man das Herumgepipe mit -print dann auf andere Programme umlegen will, dann führt das schnell zu bösen Überraschungen.



  • nman schrieb:

    jox schrieb:

    ... unnötig vielleicht im Zusammenhang damit, wenn man -exec benutzt.

    Und genau das sollte man tun.

    Mach mal ein Beispiel, wie Du das in diesem Zusammenhang nutzen willst.

    nman schrieb:

    Naja, find hat ohnehin schon ein mieses Interface, insofern ist der Mehraufwand für -exec vernachlässigbar. Außerdem ist die exec-Syntax so seltsam, dass man sie sich möglichst früh antrainieren sollte, sonst vergisst man sie garantiert. 🙂

    Das sehe ich anders, allerdings gebe ich Dir recht, die Syntax bei -exec vergisst man unter Garantie...

    nman schrieb:

    cpio kann mit Leer- und Sonderzeichen im Dateinamen recht gut umgehen, aber wenn man das Herumgepipe mit -print dann auf andere Programme umlegen will, dann führt das schnell zu bösen Überraschungen.

    Das hat wohl jemand den Algorithmus des grep-Filters nicht verstanden 😉



  • jox schrieb:

    Mach mal ein Beispiel, wie Du das in diesem Zusammenhang nutzen willst.

    Arg, stimmt, Denkfehler. cpio hat ebenfalls ein mieses Interface; ich hasse diese Oldschool-Unix-Tools. 👎

    nman schrieb:

    cpio kann mit Leer- und Sonderzeichen im Dateinamen recht gut umgehen, aber wenn man das Herumgepipe mit -print dann auf andere Programme umlegen will, dann führt das schnell zu bösen Überraschungen.

    Das hat wohl jemand den Algorithmus des grep-Filters nicht verstanden 😉

    Das hat nichts mit grep zu tun, viele Tools können einfach mit nicht maskierten Sonderzeichen (zB Whitespaces) im Dateinamen nicht umgehen, wie sie find naturgemäß ausspuckt.

    ~ % touch loesch\ mich\ bitte
    ~ % find . -iname 'loesch mich bitte'
    ./loesch mich bitte
    ~ % find . -name 'loesch mich bitte' -print
    ./loesch mich bitte
    


  • nman schrieb:

    ...ich hasse diese Oldschool-Unix-Tools.

    Ich nicht. Häufig ist das leider der kleinste gemeinsame Nenner, wenn man (so wie ich) gezwungen bzw. gewillt ist, auf diversen Unix-Derivaten zu arbeiten und kompatible Scripts zu entwickeln.

    nman schrieb:

    Das hat nichts mit grep zu tun, viele Tools können einfach mit nicht maskierten Sonderzeichen (zB Whitespaces) im Dateinamen nicht umgehen, wie sie find naturgemäß ausspuckt.

    ~ % touch loesch\ mich\ bitte
    ~ % find . -iname 'loesch mich bitte'
    ./loesch mich bitte
    ~ % find . -name 'loesch mich bitte' -print
    ./loesch mich bitte
    

    ... nur so, das Beispiel habe ich verstanden. Auch wenn irgendwelche Tools ggf. nicht mehr mitspielen, ist zumindest das ein guter Grund, diese Files zu eliminieren. Dateinamen mit irgendwelchen Sonderzeichen (inkl. Blanks) haben m.E. auch einem validen Unix-System nichts zu suchen und keine Daseinsberechtigung (und das ist meine subjektive Meinung ;-). Denn der nächste Fehler kommt durch solche Files bestimmt....

    So, und jetzt können wir gerne die theoretische Diskussion beenden, denn das hat - mal wieder - mit der ursprünglichen Fragestellung nichts zu tun und abschweifende Expertendiskussionen sind zwar recht häufig interessant, aber verwirren den Fragesteller höchstens.



  • jox schrieb:

    nman schrieb:

    ...ich hasse diese Oldschool-Unix-Tools.

    Ich nicht. Häufig ist das leider der kleinste gemeinsame Nenner

    Das "leider" schreit förmlich "Ich auch". :p

    Dateinamen mit irgendwelchen Sonderzeichen (inkl. Blanks) haben m.E. auch einem validen Unix-System nichts zu suchen und keine Daseinsberechtigung (und das ist meine subjektive Meinung ;-).

    Egal, wie Du Deine Dateien benennst: Sonderzeichen und Spaces im Dateinamen sind - glücklicherweise - erlaubt und daher musst Du beim Entwickeln Deiner Software darauf Rücksicht nehmen.

    ...aber verwirren den Fragesteller höchstens.

    Stimmt. Daher nochmal an den OP:

    Folgende Lösung von jox funktioniert und ist die brauchbarste genannte:

    find /path/to/source -name '*.[hc]' -print | cpio -pdvm /path/to/target
    


  • Hi,
    geht das hier auch, oder muss man da noch was in " einschließen?

    find /path/to/source -name '*.[hc]' -exec cp '{}' /path/to/dest/`dirname '{}'`/ \;
    

    😮 Ist doch etwas kriptischer gewurden als gedacht :p

    MfG

    AlexanderS



  • AlexanderS schrieb:

    geht das hier auch, oder muss man da noch was in " einschließen?

    find /path/to/source -name '*.[hc]' -exec cp '{}' /path/to/dest/`dirname '{}'`/ \;
    

    Was ist der Hintergrund Deiner Frage? Hat was nicht richtig geklappt????

    Sonst aber schon korrekt verstanden, im Prinzip so ähnlich (ungetestet):

    find /path/to/source -name '*.[hc]' -exec cp -p {} /path/to/dest/`dirname {}` \;
    

    - aber mit der Option -p beim copy-Kommando, damit eine nicht existierende Zieldirectory angelegt wird
    - ggf. muss man bei der Selektion mittels -name die Kriterien so einschränken, dass nur wirkliche .h und .c Files ausgesucht werden. Ich bin mir nicht sicher, ob z.B. der Punkt mit einem Backslash als Escape-Character versehen werden muss, also z.B. -name '*\.[hc]' ,i.d.R muss das ausprobiert werden, vielleicht auch 2 oder 3 Backslash-Zeichen (das ist auch systemabhängig 😉 => Sonst findet vielleicht das find-Kommando auch eine Directory mit der Endung "h" oder "c", damit kommt dann vermutlich das copy-Kommando nicht zurecht.
    - wann das Kommando "dirname" interpretiert wird, ist auch fraglich. Ich schätze mal, sofort, also nicht beim Ausführen des exec-Kommandos. D.h., auch hier sind ein od. mehrere Backslash-Zeichen notwendig (habe grad kein Unix-System am Laufen zum Austesten)

    Falls man das Kommando irgendwann zum Laufen bekommt, sieht man aber zwei entscheidende Nachteile:
    (1) Es erfolgt keine Ausgabe der kopierten Dateien (wie z.B. bei "find ... | cpio ... "), naja, das bekommt man noch mit der Option -v beim "cp" hin.
    (2) Das Konstrukt braucht einfach bei vielen Dateien ziemlich lange, weil für jede Datei das Kommando "cp" erneut gestartet wird. Bei 100 gefundenen Files werden man so locker 201 Prozesse gestartet (1 find, 100 cp, 100 dirname), beim "find ... | cpio ..." gibts nur 2 Prozesse.

    Fazit:
    Das gute alte "find ... | cpio ... " ist die adäquate Lösung für das Problem.

    P.S.: Im Prinzip kann man es auch noch mit einem "tar" hinbekommen, aber das ist eine noch ältere Variante und etwas schwieriger hinzubekommen. (Hab' ich aber auch schon mal gemacht, weil das andere in irgendeinem Zusammenhang nicht klappte). Die "tar" Variante ist nicht wirklich besser und in diesem Zusammenhang höchstens als Denksportaufgabe zu betrachten 😉

    P.P.S.: Ach so, die Option "-follow" beim find-Kommando ist sehr nützlich, wenn auch symbolische Subdirectory-Links durchforstet werden sollen.



  • Was habt ihr eigentlich alle gegen die exec-Syntax? Ich benutze die fast täglich, und habe mir sogar (u.a.) für find extra Cygwin auf die XP-Büchse installiert. 😉



  • LordJaxom schrieb:

    Was habt ihr eigentlich alle gegen die exec-Syntax? Ich benutze die fast täglich, und habe mir sogar (u.a.) für find extra Cygwin auf die XP-Büchse installiert. 😉

    Nix. Ich bin der Meinung, soll doch jeder das benutzen, was er will und wo er besser mit zurechtkommt.

    Gegenfrage: Was habt ihr eigentlich alle gegen das "cpio"? 😉



  • Vielen Dank Euch allen,

    hab jetzt nur

    find /path/to/source -name '*.[hc]' -print | cpio -pdvm /path/to/target
    

    probiert; klappt einwandfrei. Kann mir noch jemans sagen, was die Optionen

    pdvm

    machen? Die man-Seite von cpio ist nicht sehr aussagekräftig 😕

    Ansonsten: Vielen Herzlichen Dank!!!

    Gruß, Luutsch



  • Bei vielen GNU-Tools ist die Info-Seite lesbarer. Oder Du probierst die BSD-Seite zu cpio: man: cpio


Anmelden zum Antworten