Die Suche schlägt mit "Zu viele Argumente" in Shell Script fehl, jedoch nicht, wenn sie direkt in einem Terminal ausgeführt wird

586
Nestarion

Ich habe eine Workstation, auf der Bilder temporär gespeichert werden, bevor komprimierte Versionen zur sicheren Aufbewahrung auf einen Server hochgeladen werden. Ich habe ein Interesse daran, alte Dateien einmal täglich um 3 Uhr morgens mit einem über launchd geplanten Skript zu löschen.

#!/bin/bash find /some/directory/with/pictures/* -exec rm -rf {} \+ 

Ich habe dies auf einer Entwicklungs-Workstation mit nur ca. 250 MB an Bildern (30 Bilder) überprüft.

Da auf den Produktionsarbeitsstationen dieses Skript nicht ausgeführt wurde, haben sie viele Bilder in der Größenordnung von mehreren hundert Gigabyte. Das heißt, wenn findes über das Shell-Skript ausgeführt wird, stoppt es und sagt "Zu viele Argumente".

Ich verbrachte viel Zeit mit dem Versuch, herauszufinden, warum (versucht xargs, wenn Sehen Wechsel +zu ;betroffen etwas ... etc) das einzige, was ich nicht versuchen, tatsächlich wurde über das Shell - Skript in das Verzeichnis gehen insgesamt zu vermeiden verwenden zu finden. Ich denke, die "Too Many Arguments" sind sinnvoll - es klingt nach einer Obergrenze für die Anzahl der Argumente, und ich habe ~ 33.000 Dateien auf der einen Workstation, auf der ich dieses Konzept beweise.

Um die Dinge für mich noch mehr zu verwirren, find ./ -exec rm -rf {} \;funktioniert die Ausführung im Verzeichnis selbst über das Terminal (langsam).

Ich habe das Löschen mit dem Terminal durchgeführt, sodass ich mir in Zukunft keine Sorgen um den Prozess machen muss (es werden nicht annähernd 33.000 Bilder pro Tag produziert), aber ich möchte wissen, warum find im Terminal 33k arbeitet Argumente, aber nicht in einem Shell-Skript.

2
Ihr Skript und das, was Sie in dem Verzeichnis ausführen, ist nicht genau das Gleiche. Das "*" in Ihrem Skript löst möglicherweise eine Shell-Erweiterung aus, die eine Begrenzung der Befehlszeilenlänge überschreiten könnte. Mokubai vor 5 Jahren 2
Würde das Ändern der Shell-Skriptzeile in `find ./some/directory/with/pictures/ -exec rm -rf {} \ +` gleichwertig sein? Ich hatte Probleme mit früheren Iterationen, bei denen ich auch den Ordner mit den Dateien löschte. Edit: Es ist nicht gleichwertig. Es löscht den Ordner wie erwartet. Nestarion vor 5 Jahren 0
@Nestarion Versuchen Sie `find ./some/directory/with/pictures/ -mindepth 1 -exec rm -rf {} \ +` (natürlich in einem Testverzeichnis). Das `-mindepth 1` sollte verhindern, dass das Verzeichnis selbst gelöscht wird. Gordon Davisson vor 5 Jahren 0
`find. / some / verzeichnis / mit / pictures /` funktioniert nicht, aber das Entfernen des Punktes funktioniert, wenn ich -mindepth 1` hinzugefügt habe, wie Sie es vorgeschlagen haben. Bei dieser Frage ging es jedoch mehr darum, warum und wie `find` eher begrenzt ist als um die Syntax meines Befehls (obwohl verwandt). Nestarion vor 5 Jahren 0

1 Antwort auf die Frage

0
cawwot

Sie haben die * nix- Ausgabe " zu viele Dateien geöffnet " gefunden! Macos hat eine Begrenzung für die Anzahl der Dateien, die ein Prozess gleichzeitig öffnen kann. Dies entspricht in etwa der ulimitInteraktion mit Init auf den meisten Linux-Systemen.

Diese Grenzwerte werden getrennt für das Terminal und für dateisystembasierte Anwendungen festgelegt. Die Standardgrenzen jedes Prozesses werden von launchd auf Macs (seit Leopard oder so) geerbt. Sie können sie bei der Kompilierung mit sehensudo launchctl limit

Es gibt Möglichkeiten, diese Einstellung zu ändern, z. B. Wie kann der maximale Systemressourcenverbrauch auf dem Mac dauerhaft kontrolliert werden? , und welcher Befehl steuert die Grenzen der geöffneten Datei?

Die von Ihnen bereitgestellten Links sind sehr hilfreich. Genau das habe ich gesucht! Nestarion vor 5 Jahren 0
-1. In diesem Fall öffnet `find` keine Dateien, die aus der Erweiterung von` * `resultieren. Wenn diese Aktion nur bestätigt wird, müssen diese Verzeichniseinträge gelesen werden. Das Tool öffnet zwar Verzeichnisse (sofern vorhanden), tut dies jedoch nacheinander: Es schließt eines, bevor das nächste geöffnet wird. `rm` öffnet auch keine Dateien, sondern hebt sie nacheinander auf. "Zu viele Argumente" ist nicht "Zu viele offene Dateien". Kamil Maciorowski vor 5 Jahren 1
@KamilMaciorowski Laut "man find" auf meinem System find _ sucht GNU find den an jedem Startpunkt verwurzelten Verzeichnisbaum, indem er den angegebenen Ausdruck von links nach rechts gemäß den Prioritätsregeln (siehe Abschnitt OPERATORS) bewertet, bis Das Ergebnis ist bekannt (die linke Seite ist falsch für und Operationen, wahr für oder), und an diesem Punkt wird mit dem nächsten Dateinamen fortgefahren. "_ Bedeutet, dass der gesamte Baum des Basisverzeichnisses _open_ ist, während der Befehl ausgeführt wird ( zu einer Definition des Wortes _open_). cawwot vor 5 Jahren 0
@cawwot `find` muss keine Dateien öffnen, um * Verzeichnisbäume * zu durchsuchen. Kein Teil des OP-Befehls öffnet tatsächlich eine Datei, die gefunden wurde. Die ausführbaren Dateien (`find`,` rm`) müssen möglicherweise mit zusätzlichen Dateien (wie Bibliotheken, Gebietsschema usw.) geöffnet werden, aber das ist es. Kamil Maciorowski vor 5 Jahren 0
@KamilMaciorowski In einer gegabelten Dateisystemdatei werden _descriptors_ durch Befehle wie "find", "rm" usw. geöffnet. Macs verwenden HFS (oder HFS + auf neueren Macs) und haben das, was Apple [Resource Forks] nennt (https: //en.wikipedia) .org / wiki / Resource_fork), die durch Dateisystembefehle geöffnet werden, einer für jede Datei (im Allgemeinen). cawwot vor 5 Jahren 0
Sie nähern sich der Überzeugung, dass Ihre Antwort möglicherweise richtig ist. Trotzdem bezweifle ich ernsthaft, dass "find" oder "rm" (oder der Dateisystemtreiber) so viele Deskriptoren gleichzeitig geöffnet halten muss, dass das Limit erreicht wird. Vernünftige Werkzeuge öffneten und schließen sie (fast) eins nach dem anderen. Wollen Sie damit sagen, dass Macs mit HFS / HFS + während eines grundlegenden Vorgangs wie dem Durchlaufen einer Verzeichnisstruktur oder dem Entfernen einer Reihe von Dateien zur Ressourcenschöpfung neigen? Kamil Maciorowski vor 5 Jahren 0
@KamilMaciorowski 1/2 Wenn Sie speziell auf [rm] (https://github.com/openbsd/src/blob/master/bin/rm/rm.c) schauen, können wir sehen, dass es von [limits.h ] (http://pubs.opengroup.org/onlinepubs/009695399/basedefs/limits.h.html), um "Maximale Anzahl von Dateien, die ein Prozess gleichzeitig geöffnet haben kann" einzuhalten. cawwot vor 5 Jahren 0
@KamilMaciorowski 2/2 [find] (https://github.com/torvalds/linux/blob/master/fs/ubifs/find.c) hat jedoch keine solche Beschränkung und ist nur durch die maximale Heap-Größe und max_int begrenzt . Insbesondere können wir in der Funktion ubifs_find_free_space (beginnend bei Zeile 493) sehen, dass für jedes _match_ mit den `find`-Kriterien ein Dateideskriptor geöffnet wird (so werden die Dateien schließlich mit Ihren` find '-Kriterien abgeglichen). Das Problem der OPs ist höchstwahrscheinlich die maximale Anzahl von Übereinstimmungen. cawwot vor 5 Jahren 0
Ich bin kein Programmierer, aber: (A) Ich kann `OPEN_MAX` in` rm.c` nicht finden, zu dem Sie einen Link erstellen. (B) Dieses `find.c` ist Teil von [UBIFS] (https://en.wikipedia.org/wiki/UBIFS). Ich weiß nicht, warum es im Zusammenhang mit `find (1)` und HFS eine Rolle spielen sollte. Kamil Maciorowski vor 5 Jahren 0
@ KamilMaciorowski Ah, du hast recht, ich habe Grenzen gesehen. Ich nahm an. Betrachtet man jedoch die Funktion rm_tree func von `rm` (Startlinie 131), wird nie ein Baum erstellt, sondern es wird nur Element für Element durchlaufen. Dies ist im Vergleich zu find (from [findutils] (https://ftp.gnu.org/pub/gnu/findutils/), was auf Macos enthalten ist. Ich bin mir ziemlich sicher, dass ich mit dem falschen Fund verbunden war Vor). Mit tree.c wird der gesamte Baum aufgenommen, wobei jede Datei nach ihrem Eintreffen angezeigt wird. Dies würde, sofern ich mich nicht irrtümlich irre, eine Ressource-Verzweigung jeder Datei und jedes Verzeichnisses in einem Inode öffnen, bis das Aufnehmen, Gehen und Optimieren abgeschlossen ist der Baum. cawwot vor 5 Jahren 0
Ich bin kein Programmierer, aber: (C) Die allererste Zeile von `tree.c` sagt` tree.c - Hilfsfunktionen zum Erstellen und Auswerten des Ausdrucksbaums`. Der Ausdrucksbaum organisiert Operanden, nicht Dateien / Verzeichnisse. (D) Mac verwendet standardmäßig BSD `find`. Ich glaube jedoch, dass Sie GNU-Dienstprogramme auf Anforderung installieren können. Kamil Maciorowski vor 5 Jahren 0
@ KamilMaciorowski Ich bin nicht 100% sicher, ich bin auch kein Programmierer und ich habe momentan keinen Mac, um ihn persönlich zu sehen. Es scheint mir jedoch, dass BSD `find` mehr oder weniger das Gleiche tut, aber anstatt einen Baum zu bauen, führt es Ketten von Vergleichs-Executoren (die ein vergleichbares Verhalten in Bezug auf das Öffnen von Dateien angeben). Ich bin offen dafür, dass ich mich als falsch erwiesen habe. Das fühlt sich einfach so an, als würde es mir hier passieren. cawwot vor 5 Jahren 0