Listen Sie alle Verzeichnisse auf, in denen KEINE Datei mit einem bestimmten Dateinamen enthalten ist

11

Wie würde ich alle Verzeichnisse auflisten, in denen sich keine Datei mit einem bestimmten Dateinamen befindet? zB diesen Baum gegeben

/
  /a
     README
     file001
     file002
  /b
     README
     file001
  /c
     file003

Ich möchte die Verzeichnisse auflisten, die keine Datei mit dem Namen READMEhaben. In diesem Fall handelt es sich um ein Verzeichnis /c. Wie würde ich das machen? Ich kann mir keine Syntax vorstellen, die z find.

Renan
quelle
Schade, oh Schade, dass Sie nicht einmal gesucht haben: askubuntu.com/questions/196960/…
slm
Wahrscheinlich habe ich bei der Suche nicht an die richtigen Schlüsselwörter gedacht.
Renan
2
Ich bin nur kaputt in deinen Koteletts. Ich war schon viele Male dort, wo mir nicht das richtige Wort für die Suche nach etwas einfiel 8-).
slm
Verwandte: askubuntu.com/questions/196960/…
Ciro Santilli 事件 改造 中心. 法轮功 事件

Antworten:

5

Angenommen, eine findImplementierung wie GNU findakzeptiert ein {}in ein Argument eingebettetes Argument für -exec:

$ find . -type d \! -exec test -e '{}/README' \; -print

Beispiel

Hier haben die Verzeichnisse 1/1 bis 5/5 eine README, die anderen Verzeichnisse sind leer.

$ tree 
.
|-- 1
|   `-- 1
|       `-- README
|-- 10
|   `-- 10
|-- 2
|   `-- 2
|       `-- README
|-- 3
|   `-- 3
|       `-- README
|-- 4
|   `-- 4
|       `-- README
|-- 5
|   `-- 5
|       `-- README
|-- 6
|   `-- 6
|-- 7
|   `-- 7
|-- 8
|   `-- 8
`-- 9
    `-- 9

Wenn wir nun diese Version unseres findBefehls ausführen :

$ find . -type d \! -exec test -e '{}/README' \; -print
.
./10
./10/10
./7
./7/7
./9
./9/9
./6
./6/6
./5
./8
./8/8
./4
./1
./3
./2

Verweise

slm
quelle
So ändern Sie den Befehl, um nach Unterverzeichnissen zu suchen, die keine bestimmte Dateierweiterung haben (z. B. * .txt). Das Ändern von README mit * .txt scheint nicht zu funktionieren
WanderingMind
@ WanderingMind - wenn Sie eine neue Frage haben, stellen Sie sie bitte als neue auf der Website ;-)
slm
3

Sie können die -execOption verwenden find, um nach der Datei zu suchen und dann alle Ergebnisse zu drucken, für die die Prüfung fehlschlägt.

find /path/to/base -mindepth 1 -maxdepth 1 -type d -exec test -e {}/README \; -o -print
Patrick
quelle
3

Keine Notwendigkeit für find. Verwenden Sie einfach die Shell:

for d in */; do [ -f "$d"README ] || printf '%s\n' "$d"; done
c/

Wenn Sie es benötigen rekursiv zu sein, können Sie (für bash, zshkönnen dies tun , verwenden standardmäßig set -o globstarin ksh93):

shopt -s globstar
for d in **/; do [ -f "$d"README ] || printf '%s\n' "$d"; done

(Beachten Sie, dass Punktdateien standardmäßig ausgeschlossen sind).

terdon
quelle
2

Mit zshund Glob-Qualifikationsmerkmale ( eZeichenfolge ):

print -rl -- *(/e_'[[ ! -f $REPLY/README ]]'_)

oder

print -rl -- *(/^e_'[[ -f $REPLY/README ]]'_)

Hinzufügen D, um versteckte Verzeichnisse einzuschließen:

print -rl -- *(D/e_'[[ ! -f $REPLY/README ]]'_)

/wählt nur Verzeichnisse aus und e_'[[ ! -f $REPLY/README ]]'_wählt ferner nur die Verzeichnisnamen aus, für die der Shell-Code zwischen den Anführungszeichen zurückgegeben truewird, $REPLYdh für jeden Verzeichnisnamen ( ), auf den der Glob *(/)erweitert wird, wird er ausgeführt [[ ! -f $REPLY/README ]]und behält den Namen des Verzeichnisses bei, wenn das Ergebnis lautet true.
Die zweite Form ^e_'.....'_verwendet dasselbe Glob-Qualifikationsmerkmal, negiert (diesmal wird der bedingte Ausdruck jedoch nicht negiert :) [[ -f $REPLY/README ]].


Das oben Gesagte gibt nur Verzeichnisnamen im aktuellen Verzeichnis zurück.
Wenn Sie rekursiv suchen möchten (um versteckte Verzeichnisse einzuschließen, fügen Sie das DQualifikationsmerkmal hinzu):

print -rl ./**/*(/e_'[[ ! -f $REPLY/README ]]'_)
don_crissti
quelle
2

Tragbar könnten Sie tun:

find . -type d -exec sh -c '
  for dir do
    [ -f "$dir/README" ] || printf "%s\n" "$dir"
  done' sh '{}' +

[ -f file ]Testet, ob die Datei vorhanden ist und als reguläre Datei bestätigt wurde (nach Symlink-Auflösung).

Wenn Sie testen möchten, ob es nur existiert (als Eintrag in diesem Verzeichnis), unabhängig von seinem Typ, benötigen Sie: [ -e file ] || [ -L file ]Beachten Sie jedoch, dass Sie eine Suchberechtigung für das Verzeichnis benötigen, um diese Tests durchzuführen. Möglicherweise möchten Sie einige [ -x "$dir" ]Tests hinzufügen , um folgende Fälle zu berücksichtigen:

find . -type d -exec sh -c '
  for dir do
    if [ -x "$dir" ]; then
      [ -f "$dir/README" ] || printf "%s\n" "$dir"
    else
      printf >&2 "Cannot tell for \"%s\"\n" "$dir"
    fi
  done' sh '{}' +

Oder um die Rennbedingungen zu vermeiden, mit zsh:

find . -type d -exec zsh -c '
  zmodload zsh/system
  for dir do
    ERRNO=0
    if [ ! -f "$dir/README" ]; then
      if [ "$errnos[ERRNO]" = ENOENT ]; then
        printf "%s\n" "$dir"
      else
        syserror -p "ERROR: $dir/README: "
      fi
    fi
  done' zsh '{}' +

Siehe auch Wie kann ich feststellen, ob in Bash keine reguläre Datei vorhanden ist? auf SO.

Stéphane Chazelas
quelle