Damit gibt es mehrere Probleme
set *
if [ -e "$1" ]
then
echo 'not empty'
else
echo 'empty'
fi
Code:
- wenn die
nullglobOption (ab zshjetzt aber von den meisten anderen Shells unterstützt) aktiviert ist, set *wird , setwelche 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 dotgloboder globdotOption oder das Spiel mit einer FIGNOREspeziellen 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 ..), zshist das FGlob-Qualifikationsmerkmal ( Ffü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
Nist das nullglobGlob-Qualifikationsmerkmal. Erweitert .(NF)sich also, .wenn .voll ist und sonst nichts.
Nachdem die lstat()auf dem Verzeichnis, wenn zshes 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 zshsich in der shEmulation 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 zshdie 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 zshvon 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, tcshund fishnicht 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 zshsei denn, Sie aktivieren die shEmulation.
Diese shEmulation ist besonders vorhanden, damit Sie POSIX-Code in verwenden können zsh.
Wenn Sie möchten , sourceeine Datei in POSIX geschrieben shinnen zsh, können Sie tun:
emulate sh -c 'source that-file'
Dann wird diese Datei in der shEmulation ausgewertet und jede darin deklarierte Funktion behält diesen Emulationsmodus bei.