Damit gibt es mehrere Probleme
set *
if [ -e "$1" ]
then
echo 'not empty'
else
echo 'empty'
fi
Code:
- wenn die
nullglob
Option (ab zsh
jetzt aber von den meisten anderen Shells unterstützt) aktiviert ist, set *
wird , set
welche Listen Sie alle Shell - Variablen (und Funktionen in einigen Muscheln)
- Wenn die erste nicht ausgeblendete Datei einen Namen hat, der mit
-
oder beginnt +
, wird sie von als Option behandelt set
. Diese beiden Probleme können stattdessen behoben werden set -- *
.
*
Erweitert nur nicht versteckte Dateien. Es ist also kein Test, ob das Verzeichnis leer ist oder nicht, sondern ob es nicht versteckte Dateien enthält oder nicht. Mit einigen Muscheln und Sie können verwenden dotglob
oder globdot
Option oder das Spiel mit einer FIGNORE
speziellen variabel in Abhängigkeit von der Schale zu arbeiten um die.
[ -e "$1" ]
Testet, ob ein stat()
Systemaufruf erfolgreich ist oder nicht. Wenn die erste Datei ein Symlink zu einem unzugänglichen Speicherort ist, wird false zurückgegeben. Sie sollten keine Datei stat()
(nicht einmal lstat()
) benötigen, um zu wissen, ob ein Verzeichnis leer ist oder nicht. Überprüfen Sie nur, ob es Inhalt enthält.
*
Bei der Erweiterung wird das aktuelle Verzeichnis geöffnet, alle Einträge abgerufen, alle nicht ausgeblendeten gespeichert und sortiert, was ebenfalls ineffizient ist.
Der effizienteste Weg, um zu überprüfen, ob ein Verzeichnis nicht leer ist (mit einem anderen Eintrag als .
und ..
), zsh
ist das F
Glob-Qualifikationsmerkmal ( F
für vollständig , hier nicht leer):
if [ .(NF) ]; then
print . is not empty
else
print "it's empty or I can't read it"
fi
N
ist das nullglob
Glob-Qualifikationsmerkmal. Erweitert .(NF)
sich also, .
wenn .
voll ist und sonst nichts.
Nachdem die lstat()
auf dem Verzeichnis, wenn zsh
es hat Funde eine Link-Zähler größer als 2 ist , dann das bedeutet , es hat zumindest ein Unterverzeichnis so leer ist , nicht, so dass wir dieses Verzeichnis nicht einmal öffnen müssen (das bedeutet auch, dass In diesem Fall können wir feststellen, dass das Verzeichnis nicht leer ist, auch wenn wir keinen Lesezugriff darauf haben. Andernfalls öffnet zsh das Verzeichnis, liest seinen Inhalt und stoppt beim ersten Eintrag, der weder .
noch ..
ohne Lesen, Speichern oder Sortieren alles ist.
Bei POSIX-Shells (die zsh
sich in der sh
Emulation nur (mehr) POSIX verhalten ) ist es sehr umständlich zu überprüfen, ob ein Verzeichnis nur mit Globs nicht leer ist.
Ein Weg ist mit:
set .[!.]* '.[!.]'[*] .[.]?* [*] *
if [ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]; then
echo "empty or can't read"
else
echo not empty
fi
(unter der Annahme, dass keine globbezogene Option gegenüber der Standardeinstellung geändert wird (POSIX gibt nur an noglob
) und dass die Variablen GLOBIGNORE
(für bash
) und FIGNORE
(für ksh
) nicht festgelegt sind und dass (für yash
) keiner der Dateinamen Folgen von Bytes enthält, die keine gültigen Zeichen bilden ).
Die Idee ist, dass in POSIX-Shells ein Globus, wenn er nicht übereinstimmt, nicht erweitert wird (eine Fehlfunktion, die die Bourne-Shell Ende der 70er Jahre eingeführt hat). Also mit set -- *
, wenn wir bekommen $1
== *
, wir wissen nicht , ob es war , weil es keine Übereinstimmung war oder ob es eine Datei mit dem Namen *
.
Ihr (fehlerhafter) Ansatz, um das zu umgehen, war zu verwenden [ -e "$1" ]
. Hier verwenden wir stattdessen set -- [*] *
. Dies ermöglicht es, die beiden Fälle zu unterscheiden, denn wenn keine Datei vorhanden ist, bleibt die oben genannte bestehen [*] *
, und wenn eine Datei aufgerufen *
wird, wird dies * *
. Ähnliches tun wir für versteckte Dateien. Das ist etwas umständlich, da die Bourne-Shell (ebenfalls behoben durch zsh
die Forsyth-Shell, pdksh und fish
) eine weitere Fehlfunktion aufweist, bei der die Erweiterung von .*
die speziellen (Pseudo-) Einträge enthält .
und von ..
gemeldet wird readdir()
.
Damit es in all diesen Muscheln funktioniert, können Sie Folgendes tun:
cwd_empty()
if [ -n "$ZSH_VERSION" ]; then
eval '! [ .(NF) ]'
else
set .[!.]* '.[!.]'[*] .[.]?* [*] *
[ "$#$1$2$3$4$5" = '5.[!.]*.[!.][*].[.]?*[*]*' ]
fi
In jedem Fall ist die Syntax zsh
von standardmäßig nicht mit der POSIX sh-Syntax kompatibel, da sie die meisten Hauptprobleme in der Bourne-Shell (lange bevor POSIX.2 erstmals veröffentlicht wurde) auf nicht abwärtskompatible Weise behoben hat, einschließlich dieser *
links unexpanded wenn es keine Übereinstimmung ist (pre-Bourne - Shells nicht das Problem hatte, csh
, tcsh
und fish
nicht entweder) und .*
darunter .
und ..
aber einige andere wie Split + glob auf Parameter oder arithmetische Erweiterung durchgeführt, so dass Sie nicht erwarten können Code geschrieben in der POSIX sh, um immer zu arbeiten, es zsh
sei denn, Sie aktivieren die sh
Emulation.
Diese sh
Emulation ist besonders vorhanden, damit Sie POSIX-Code in verwenden können zsh
.
Wenn Sie möchten , source
eine Datei in POSIX geschrieben sh
innen zsh
, können Sie tun:
emulate sh -c 'source that-file'
Dann wird diese Datei in der sh
Emulation ausgewertet und jede darin deklarierte Funktion behält diesen Emulationsmodus bei.