
Hallo Liste, ich bräuchte Hilfe zu einer Kombination von find und tar. Ich stehe in einem Verzeichnis mit vielen Unterverzeichnissen, in den Dateien eines bestimmten Typs sind (z. B. pptx und xlsx), die ich in ein Archiv packen möchte. Manche Unterverzeichnisse möchte ich jedoch ausschließen. Für 1 Unterverzeichnis ist mir das gelungen. Mein Befehl sieht so aus: find -L . -path './Verzeichnis_AA' -prune -o -type f -regex ".*\.\(pptx\|xlsx\)" -exec tar -rvf Sicherung_pptx_xlsx.tar {} \; Wie muss der Befehl aussehen, wenn ich noch Verzeichnis_BB oder evtl. noch ein weiteres Verzeichnis_CC ausschließen möchte? Gruß Herbert

hab nun doch noch einen Hinweis gefunden, den ich etwas abgewandelt habe. find -L . \( -path './Verzeichnis_AA' -prune \) -o \( -path './Verzeichnis_BB' -prune \) -o -type f -regex ".*\.\(pptx\|xlsx\)" -exec tar -rvf Sicherung_pptx_xlsx.tar {} \; Ist das die Lösung, dass ich alle auszuschließenden Verzeichniss so angeben muss? Kann man find nicht auch eine Liste der Verzeichnisse in Form einer ASCII Datei übergeben?

Ja, vielleicht geht das auch in 3 Schritten, dann aber nicht mit exclude sondern mit dem Gegenteil. 1. Schritt find mind Umleitung in eine Datei 2. Datei auf das wichtige bereinigen (auch in gewollten Verzeichnissen sind einige Dateien, die nicht benötigt werden 3. Schritt tar mit der Dateiliste. Doch wie lautet der tar Befehl um eine Liste zu übergeben? Das habe ich noch nicht gefunden.

Hallo, Am Fr, 12 Aug 2022, Herbert Albert schrieb:
Ja, vielleicht geht das auch in 3 Schritten, dann aber nicht mit exclude sondern mit dem Gegenteil. 1. Schritt find mind Umleitung in eine Datei
Unnötig.
3. Schritt tar mit der Dateiliste. Doch wie lautet der tar Befehl um eine Liste zu übergeben? Das habe ich noch nicht gefunden.
$ tar --help |grep file [..] -T, --files-from=FILE get names to extract or create from FILE [..] Am besten nimmt man gleich die ASCII NUL als Trennzeichen, also: find ... -print0 | tar -cv -f foo.tar --null --files-from=- (Kompression beim tar ggfs. ergänzen oder anschließend händisch erledigen). HTH, -dnh -- Woher bloß Mütter all das kennen, was sie ihren Töchtern verbieten...

Am Freitag, 12. August 2022, 10:59:25 CEST schrieb David Haller:
mit dem Aufbau find ... -print0 | tar -cv -f foo.tar --null --files-from=- habe ich nun ein Verständnisproblem. Mit dem find Befehl muss ich ja erst einmal alle Files finden, die dem Kriterium genügen. Wandern die mit "print0" in eine Liste im Speicher, die dann mit "--files-from=-" ausgelesen wird? Was ich mit meinem Vorschlag der 3 Stufen meinte ist - zwar etwas umständlich, doch so oft muss ich das nicht machen - erst eine Datei mit der Fileliste zu erzeugen, diese dann bereinigen, und dann einen tar Befehl übergeben. Gruß Herbert

Hallo, Am Fr, 12 Aug 2022, Herbert Albert schrieb:
find schreibt die Dateinamen, getrennt durch ein ASCII NUL ('\0') in die PIPE, aus der tar dann liest, an den '\0' die Dateinamen trennt, und die Dateien einsammelt und ins tar einpackt.
Das "bereinigen" solltest du, so du es irgendwie hinbegkomst, so wie du schon angefangen hast, mit find erledigen. Das Zusammenspiel von ein- und ausschließenden Kriterien bei find ist nicht immer leicht. '-path', '-o', '-prune', usw. usf... Ich muß da auch jedesmal rumprobieren. Ich versuch's aber mal mit deinem Beispiel, erstmal mit -print statt -print0, so daß das experimentieren (z.B. mit '|less' oder '>datei') einfacher fällt: (BTW: Bist du dir GAAANZ sicher, daß die Dateien alle '*.xslx' heißen und nicht etwa '*.XSLX'? -> also besser '-iregex' ;) $ find -L . -type f -iregex ".*\.\(pptx\|xlsx\)" \ -not \( \ -path './Verzeichnis_AA/*' \ -o -path './Verzeichnis_BB/*' \ ... \ -o -path './Verzeichnis_ZZ/*' \ \) -print Ist evtl. nicht effizient von der Suche her... Erst alle Unterordner abklappern und _dann_ erst wegwerfen, daher siehe weiter unten das zweite Muster. Desweiteren: bei dem '-not \( .. \)' ist das Muster so, daß in den '\( ... -o ... -o ... \)' _zwischen_ den Kriterien jew. ein '-o' stehen muß. Durch die \(\) wird alles dazwischen (verodert) negiert, Also: bla ... "-abernicht" VerzA "-noch" VerzB ... "-noch" VerzZ Wichtig ist hier generell: ==== man find ==== -path pattern File name matches shell pattern pattern. [..] Note that the pattern match test applies to the whole file name, ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ starting from one of the start points named on the command line. ==== Hervorhebung von mir. Das '-path' betrachtet _DEN GESAMTEN NAMEN_, daher ist das abschließende '/*' zwingend, wie du selber auch ausprobieren kannst. Bsp (das 2>/dev/null wg. "Permission denied" als non-root ;): $ find /tmp/ -not -path '/tmp/' 2>/dev/null | wc -l 989 $ find /tmp/ -not -path '/tmp/*' 2>/dev/null | wc -l 0 $ Siehste den Unterschied, oder? Und ggfs., falls es sich eben nicht um Shell-Muster (Globs) am Anfang handelt, muß auch dort natürlich zwingend ein '*' hin: $ find /tmp/ -not -path '/dh/' 2>/dev/null | wc -l 989 $ find /tmp/ -not -path '*/dh/*' 2>/dev/null | wc -l 775 (Ja, viel Müll im nicht tmpfs /tmp, aber seit tmpfs Usus ist, räumt gefühlt auch nix mehr hinter sich auf sondern läßt seinen Dreck einfach liegen, auch wenn das Programm normal und sauber beendet wird *grummel*, würde mich auch bei tmpfs maßlos ärgern, da es das RAM zumüllt, da kann ich eher das bissl Plattenplatz entbehren.) BTW: ich mag's eher mit '-[i]name' und Globs zu hantieren als mit Regexen, die lassen sich einfacher, ggfs. per Shell(-script) generieren. Wieder obiges: find -L . -type f \ \( -iname '*.docx' \ -o -iname '*.pptx' \ ... \ -o -iname '*.xlsx' \ \) \ -not \( \ -path './Verzeichnis_AA/*' \ -o -path './Verzeichnis_BB/*' \ ... \ -o -path './Verzeichnis_ZZ/*' \ \) -print Keine Ahnung ob das bei dir so funktioniert. Ein alternatives Muster, daß funktionieren könnte: find -L . \ -path './Verzeichnis_AA/*' -prune \ -o -path './Verzeichnis_BB/*' -prune \ ... -prune \ -o -path './Verzeichnis_ZZ/*' -prune \ -o \ \( \ -iname '*.docx' \ -o -iname '*.pptx' \ ... \ -o -iname '*.xlsx' \ \) \ -print Also erstmal unerwünschte Verzeichnisse samt Unterordner rauswerfen, und _DANACH_ per _ODER_ sonstige Kriterien und dann per _UND_ das (bei GNU find implizite) -print bzw. (explizite) -print0 hintendran. (das '-o' zwischen dem letzten '-prune' und dem Rest verknotet mir auch jedesmal neu das Hirn und ich muß in Scripten nachschauen, wie das richtig geht ;) Die jew. (bis auf das jew. erste) Listen von '-o -path '*/bla/*' -prune \ und '-o -iname '*.bla' -prune \ lassen sich relativ leicht generieren, ergänzen usw. usf. falls es mal wieder mehr wird ;) IMHO meist jedenfalls einfacher, als Regexe zu ergänzen. So sehr ich Regexe liebe :) * * * So, erstmal durchschnauf * * * Zur Not kann man aber auch noch mit was anderem, das mit '\0' als Trennzeichen umgehen kann, nacharbeiten. Z.B. geht das mit GNU grep: $ find ... -print0 | grep --null-data -v 'bla' | \ tar -cv -f foo.tar --null --files-from=- Zum nachvollziehen: $ printf 'foo\0bar\0baz\0' | grep -z -v 'bar' | tr '\0' '\n' foo baz $ Oder auch mehrschrittig: $ printf 'foo\0bar\0baz\0' | od -tx1z 0000000 66 6f 6f 00 62 61 72 00 62 61 7a 00 >foo.bar.baz.< 0000014 $ printf 'foo\0bar\0baz\0' | grep -z -v 'bar' | od -tx1z 0000000 66 6f 6f 00 62 61 7a 00 >foo.baz.< 0000010 $ printf 'foo\0bar\0baz\0' | grep -z -v 'bar' | tr '\0' '\n' | od -tx1z 0000000 66 6f 6f 0a 62 61 7a 0a >foo.baz.< 0000010 $ Man beachte die '00' (aka '\0') in den ersten beiden 'od' Ausgaben (die tr dann zu '0a' (aka '\n') konvertiert). BTW: $ type hex hex is aliased to `od -tx1z' Vorteil: od gibt's überall ;) HTH, -dnh --

Ich hätte den ganzen Absatz zitieren sollen, damit du nicht glaubst, es könne einfach einfach sein (o: -T, --files-from=FILE Get names to extract or create from FILE. Unless specified otherwise, the FILE must contain a list of names separated by ASCII LF (i.e. one name per line). The names read are handled the same way as command line arguments. They undergo quote removal and word splitting, and any string that starts with a - is handled as tar command line option. If this behavior is undesirable, it can be turned off using the --verbatim-files-from option. The --null option instructs tar that the names in FILE are separated by ASCII NUL character, instead of LF. It is useful if the list is generated by find(1) -print0 predicate. Am 12.08.22 um 09:43 schrieb Herbert Albert:
-- Viele Grüße Michael Behrens
participants (3)
-
David Haller
-
Herbert Albert
-
Michael Behrens