
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 find
Implementierung wie GNU , die ein eingebettetes Argument find
akzeptiert, 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 find
Befehls 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
, zsh
kann dies standardmäßig tun, verwenden Sie set -o globstar
in 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
-exec
Mit dieser Option können Sie find
nach 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.