Erwartetes Verhalten von `find -depth`, wenn die Ausführungsberechtigung für das Unterverzeichnis verweigert wurde?

7

Ich möchte wissen, ob ich mich auf das Verhalten verlassen kann, das ich bei der Verwendung findmit -depthOption sehe, und der Benutzer keine Ausführungsberechtigung für ein Unterverzeichnis hat.

Nehmen Sie die folgende Verzeichnisstruktur an:

drwxrwxrwt. 10 root    root     12288 Mar 14 04:31 .
dr-xr-xr-x. 24 root    root      4096 Dec  6 03:33 ..
drwx------   4 root    root      4096 Mar 14 04:03 jen

Führen Sie den folgenden Befehl als Nicht-Root-Benutzer aus:

find -type d

Die Ausgabe ist:

.
./jen
find: `./jen': Permission denied

Also findfand das Verzeichnis jen und gab das aus. Es versuchte dann, in Jen abzusteigen , hatte aber keine Erlaubnis, so dass es den Fehler druckte. Die erste Zeile oben wird gedruckt stdoutund die zweite Zeile an stderr.

Führen Sie nun Folgendes als Nicht-Root-Benutzer aus:

find -depth -type d

Und die Ausgabe ist:

find: `./jen': Permission denied
.

Daher wird der Pfadname nur ausgegeben, stdoutwenn der Benutzer die Berechtigung hat, den Inhalt des Verzeichnisses aufzulisten.

Diese Ausgabe ist perfekt für das, was ich tun möchte. Ich bin mir jedoch nicht sicher, ob dies nur ein Zufall ist oder nicht. Kann ich mich auf dieses Verhalten verlassen?

Ich verwende GNU findutils 4.4.2. Ich frage mich, ob dieses Verhalten in allen Versionen von gleich ist find. Und wenn nicht, ist es zumindest für alle Versionen von GNU find gleich.

Es ist mir (für diesen Anwendungsfall) egal, ob Jen im ersten Beispiel gedruckt wird oder nicht . Ich frage mich nur , wenn ich hängen auf sie ausgeschlossen werden , wenn -depthverwendet wird. Normalerweise ist es keine gute Idee, sich auf undokumentiertes Verhalten zu verlassen. Aber für mich macht dieser Nebeneffekt Sinn. Ich denke also, dass dies das beabsichtigte Verhalten sein könnte.

Das Handbuch sagt:

- Option: -tiefe

Verarbeiten Sie den Inhalt jedes Verzeichnisses vor dem Verzeichnis selbst.

Dies ist genau das , was ich möchte, aber es ist nicht klar, dass der Pfadname des Verzeichnisses selbst von der Ausgabe ausgeschlossen wird, wenn es nicht in das Verzeichnis absteigt.

Dank eines Hinweises von Hauke ​​Laging habe ich festgestellt, dass ich nur Verzeichnisse auflisten und Verzeichnisse explizit ausschließen kann, bei denen die Berechtigung zum Auflisten ihres Inhalts verweigert wird:

find -type d \( \( -type d \( \! -executable -or \! -readable \) \) -prune -or -print \)

Dies hat auch den Effekt, dass die Fehler "Berechtigung verweigert" gestoppt werden, da findniemals versucht wird, in ein Verzeichnis abzusteigen, wenn es keine Berechtigung hat.

Leider gibt es zwei Gründe, warum dies für meine Bedürfnisse nicht funktioniert.

  • Ich möchte die Fehlermeldungen
  • Ich brauche die -depthOption

Zitat aus dem Handbuch

Wenn die Option '-depth' aktiviert ist, wurden die Unterverzeichnisse in jedem Fall bereits besucht. Daher hat '-prune' in diesem Fall keine Wirkung.

Also bin ich wieder da, wo ich angefangen habe.

Es ist immer noch nicht klar, ob "den Inhalt jedes Verzeichnisses vor dem Verzeichnis selbst verarbeitet" oder nicht. bedeutet auch "Verarbeiten Sie das Verzeichnis nicht, wenn Sie den Inhalt nicht verarbeiten können".

Toxalot
quelle
Welche Versionen von findmöchten Sie berücksichtigen? Unter Solaris 10, find . -type ddruckt "."nach stdout und "find: cannot read dir ./jen: Permission denied"stderr. find . -depth -type ddruckt "find: cannot read dir ./jen: Permission denied"nach stderr und "."nach stdout. Weder "./jen"auf Standard drucken .
Mark Plotnick
@MarkPlotnick Das Fehlen .war ein Fehler beim Kopieren und Einfügen. Ich habe meine Frage mit Details zu Versionen und den Details, auf die ich mich verlassen kann, aktualisiert.
Toxalot
@ MarkPlotnick Ich finde es seltsam, dass Solaris 10 nicht ./jenfür druckt find . -type d. Es ist immer noch Teil des Inhalts von ., obwohl findes nicht darin absteigen kann. Auf was erweitert sich das ./*Glob-Muster unter Solaris 10? Beinhaltet es ./jen?
Toxalot
Ich fand es auch unerwartet, aber genau das macht es. echo ./*Ausgänge ./jen. Ich habe die Verzeichnisstruktur so eingerichtet, dass sie mit der des OP übereinstimmt. trusszeigt , dass findtut fchdir()zum offenen "."fd, dann getdents64() = 72, lstat64("jen",...) = 0, openat(..., "jen", ...) => EACCES, gibt es dann die Fehlermeldung, dann getdents64() = 0, dann cleanup und beenden. Dies ist auf der neuesten kostenlosen Solaris 10 / x86-Distribution von Oracle, Generic_147148-26, in einer UFS-Partition
Mark Plotnick

Antworten:

2

Wahrscheinlich ist der bessere Ansatz, solche Verzeichnisse explizit zu behandeln. Ich weiß nicht, ob dies Standardfunktionen sind, aber zumindest mit Gnu ist finddies möglich:

find . \( -type d \( \! -executable -or \! -readable \) \) -prune -or -type d

Natürlich ist es auch möglich, eine Nachricht zu drucken, wenn ein Verzeichnis ignoriert wird:

find . \( -type d \( \! -executable -or \! -readable \) \) \
  -printf "Permission denied: %p\n" -prune -or -type d -print
Hauke ​​Laging
quelle
Dies ergibt nicht die gewünschte Ausgabe. Die fragliche Verzeichnisstruktur war ein Beispiel. Die reale Struktur enthält reguläre Dateien. Mit dem -or printwerden alle Dateitypen gedruckt. Ich möchte nur Verzeichnisse.
Toxalot
Neben der Notwendigkeit, reguläre Dateien auszuschließen, möchte ich auch die Fehlermeldungen beibehalten. Ich habe meine Frage aktualisiert, um dies widerzuspiegeln.
Toxalot
@toxalot Ich denke, es ist offensichtlich, dass -print(dh der Teil nach dem -or) nur ein Dummy ist, der durch alles ersetzt werden muss, was Sie wollen. ZB können Sie das ändern in -or -type d.
Hauke ​​Laging
Der zweite druckt nur Verzeichnisse, schließt Verzeichnisse aus, wenn keine Berechtigung zum Auflisten von Inhalten besteht, und druckt eine Fehlermeldung, die mich den größten Teil des Weges dorthin führt. Beachten Sie, dass das -printnach dem -or -type dwichtig ist. Sie können nicht nur ersetzen , -or -printmit -or type dwie im Kommentar vorgeschlagen. Da dies -prunejedoch keine Auswirkung hat, wenn -depthes verwendet wird, kehre ich zu meiner ursprünglichen Frage zurück.
Toxalot
@toxalot Sie können das -printfTeil nach Ihren Wünschen anpassen . Natürlich können Sie eine Zeile mit dem Pfad und eine andere mit der Fehlermeldung drucken. -printwird nach dem -ornur benötigt, wenn im ersten Teil ein Druckbefehl auftritt. Sie brauchen nicht -prune(ein Absteigen in diese Verzeichnisse ist sowieso unmöglich), damit Sie es depthproblemlos verwenden können.
Hauke ​​Laging