Listet alle Verzeichnisse auf, die KEINE Datei mit einem bestimmten Dateinamen enthalten

Listet alle Verzeichnisse auf, die KEINE Datei mit einem bestimmten Dateinamen enthalten

Wie kann ich alle Verzeichnisse auflisten, dienichtHaben Sie eine Datei mit einem bestimmten Dateinamen darin? Beispiel: dieser Baum

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

Ich möchte die Verzeichnisse auflisten, dienichthabe eine Datei mit dem Namen README, in diesem Fall wäre es das Verzeichnis /c. Wie würde ich das machen? Mir fällt keine Syntax ein, die z. B. verwendet find.

Antwort1

Angenommen, es handelt sich um eine findImplementierung wie GNU , die ein eingebettetes Argument findakzeptiert, um :{}-exec

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

oder ohne die problematische Einbettung:

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

Beispiel

Hier haben die Verzeichnisse 1/1 bis 5/5 eine README-Datei, 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 jetzt 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

Antwort2

Kein Bedarf find. Verwenden Sie einfach die Shell:

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

Wenn es rekursiv sein muss, können Sie Folgendes verwenden (für bash, zshkann dies standardmäßig tun, verwenden Sie 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).

Antwort3

-execMit dieser Option können Sie findnach der Datei suchen und anschließend alle Ergebnisse ausdrucken, bei denen die Prüfung fehlschlägt.

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

Antwort4

Portabel könnten Sie Folgendes tun:

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

[ -f file ]prüft, ob die Dateiexistiert Undwird als reguläre Datei bestätigt (nach Symlink-Auflösung).

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

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 den Race Condition 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 auchWie erkenne ich, ob eine reguläre Datei in Bash nicht vorhanden ist?auf SO.

verwandte Informationen