Mit welchem Befehl kann überprüft werden, ob in einem Bash-Shell-Skript ein Verzeichnis vorhanden ist oder nicht?
Mit welchem Befehl kann überprüft werden, ob in einem Bash-Shell-Skript ein Verzeichnis vorhanden ist oder nicht?
Antworten:
Um zu überprüfen, ob ein Verzeichnis in einem Shell-Skript vorhanden ist, können Sie Folgendes verwenden:
if [ -d "$DIRECTORY" ]; then
# Control will enter here if $DIRECTORY exists.
fi
Oder um zu überprüfen, ob kein Verzeichnis vorhanden ist:
if [ ! -d "$DIRECTORY" ]; then
# Control will enter here if $DIRECTORY doesn't exist.
fi
Wie Jon Ericson jedoch betont, funktionieren nachfolgende Befehle möglicherweise nicht wie beabsichtigt, wenn Sie nicht berücksichtigen, dass eine symbolische Verknüpfung zu einem Verzeichnis diese Prüfung ebenfalls besteht. ZB laufen lassen:
ln -s "$ACTUAL_DIR" "$SYMLINK"
if [ -d "$SYMLINK" ]; then
rmdir "$SYMLINK"
fi
Wird die Fehlermeldung erzeugen:
rmdir: failed to remove `symlink': Not a directory
Daher müssen symbolische Links möglicherweise anders behandelt werden, wenn nachfolgende Befehle Verzeichnisse erwarten:
if [ -d "$LINK_OR_DIR" ]; then
if [ -L "$LINK_OR_DIR" ]; then
# It is a symlink!
# Symbolic link specific commands go here.
rm "$LINK_OR_DIR"
else
# It's a directory!
# Directory command goes here.
rmdir "$LINK_OR_DIR"
fi
fi
Beachten Sie insbesondere die doppelten Anführungszeichen, mit denen die Variablen umbrochen werden. Der Grund dafür wird von 8jean in einer anderen Antwort erklärt .
Wenn die Variablen Leerzeichen oder andere ungewöhnliche Zeichen enthalten, schlägt das Skript wahrscheinlich fehl.
[ ! -d "$DIRECTORY" ]
Wird wahr sein, wenn $DIRECTORY
sie nicht existiert oder wenn sie existiert, aber kein Verzeichnis ist. Betrachten Sie etwas wie if [ ! -d "$DIRECTORY" ] ; then mkdir "$DIRECTORY" ; fi
; Dies schlägt fehl, wenn "$DIRECTORY"
es sich um eine Datei handelt. (Natürlich sollten Sie prüfen, ob mkdir
es trotzdem gelungen ist; es gibt eine Reihe von Gründen, warum dies fehlschlagen kann.)
-d
) als auch nach dem Symlink ( -L
) zu testen , ist es einfacher, einfach einen Schrägstrich an die Variable anzuhängen, wie z if [ -d "${THING:+$THING/}" ]
. Ein Verzeichnis hat nichts gegen den zusätzlichen Schrägstrich. Eine Datei wird als falsch ausgewertet. Leer bleibt leer, also falsch. Und ein Symlink wird zu seinem Ziel aufgelöst. Natürlich hängt es von Ihrem Ziel ab. Wenn Sie wollen , gehen Sie dort, das ist in Ordnung. Wenn Sie es löschen möchten , ist der Code in dieser Antwort besser.
Denken Sie daran, Variablen immer in doppelte Anführungszeichen zu setzen, wenn Sie in einem Bash-Skript auf sie verweisen. Kinder wachsen heutzutage mit der Idee auf, dass sie Leerzeichen und viele andere lustige Charaktere in ihren Verzeichnisnamen haben können. (Räume! Damals hatten wir keine ausgefallenen Räume !;))
Eines Tages wird eines dieser Kinder Ihr Skript mit $DIRECTORY
set to ausführen "My M0viez"
und Ihr Skript wird explodieren. Das willst du nicht. Also benutze das.
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists, even if it contains spaces
fi
Beachten Sie, dass der -d- Test einige überraschende Ergebnisse liefern kann:
$ ln -s tmp/ t
$ if [ -d t ]; then rmdir t; fi
rmdir: directory "t": Path component not a directory
Datei unter: "Wann ist ein Verzeichnis kein Verzeichnis?" Die Antwort: "Wenn es sich um einen Symlink zu einem Verzeichnis handelt." Ein etwas gründlicherer Test:
if [ -d t ]; then
if [ -L t ]; then
rm t
else
rmdir t
fi
fi
Weitere Informationen finden Sie im Bash-Handbuch zu Bash-Bedingungsausdrücken sowie im [
eingebauten Befehl und im [[
zusammengesetzten Befehl .
if [ -d tmpdir -a ! -L tmpdir ]; then echo "is directory"; rmdir tmpdir; fi
... oder für einen Befehl, der sowohl für Links als auch für Verzeichnisse funktioniert:rm -r tmpdir
Ich finde, dass die Doppelklammerversion von test
das Schreiben von Logiktests natürlicher macht:
if [[ -d "${DIRECTORY}" && ! -L "${DIRECTORY}" ]] ; then
echo "It's a bona-fide directory"
fi
if [[ -d "$TARFILE" ]]
ich bekomme [[: nicht gefunden
[[ ]]
unterstützt, bietet aber tatsächlich keine andere Funktionalität als [ ]
. Wenn die Portabilität ein Problem darstellt, halten Sie sich an [ ]
die erforderlichen Problemumgehungen und verwenden Sie diese.
Kürzere Form:
[ -d "$DIR" ] && echo "Yes"
if $dir is a dir, then echo "yes"
? Ein bisschen Erklärung würde helfen :)
cmd && other
ist eine gebräuchliche Abkürzung für if cmd; then other; fi
- dies funktioniert mit den meisten Programmiersprachen, die die Boolesche Logik unterstützen, und wird als Kurzschlussauswertung bezeichnet .
set -e
(dies ist eine bewährte Methode für die Shell-Programmierung ).
[ -d "$DIR" ]
wird überprüft (gefolgt von && echo Yes
), daher glaube ich, set -e
dass es keinen Unterschied zum Skriptverhalten macht (dh wenn der Test fehlschlägt, wird das Skript normal fortgesetzt).
Um zu überprüfen, ob ein Verzeichnis vorhanden ist, können Sie eine einfache if
Struktur wie die folgende verwenden:
if [ -d directory/path to a directory ] ; then
# Things to do
else #if needed #also: elif [new condition]
# Things to do
fi
Sie können es auch negativ machen:
if [ ! -d directory/path to a directory ] ; then
# Things to do when not an existing directory
Hinweis : Seien Sie vorsichtig. Lassen Sie auf beiden Seiten der öffnenden und schließenden Klammern leere Stellen.
Mit der gleichen Syntax können Sie verwenden:
-e: any kind of archive
-f: file
-h: symbolic link
-r: readable file
-w: writable file
-x: executable file
-s: file size greater than zero
Ein einfaches Skript zum Testen, ob ein Verzeichnis oder eine Datei vorhanden ist oder nicht:
if [ -d /home/ram/dir ] # For file "if [-f /home/rama/file]"
then
echo "dir present"
else
echo "dir not present"
fi
Ein einfaches Skript, um zu überprüfen, ob das Verzeichnis vorhanden ist oder nicht:
mkdir tempdir # If you want to check file use touch instead of mkdir
ret=$?
if [ "$ret" == "0" ]
then
echo "dir present"
else
echo "dir not present"
fi
Die obigen Skripte prüfen, ob das Verzeichnis vorhanden ist oder nicht
$?
Wenn der letzte Befehl erfolgreich ist, wird "0" zurückgegeben, andernfalls ein Wert ungleich Null. Angenommen, es tempdir
ist bereits vorhanden. Dann mkdir tempdir
wird ein Fehler wie folgt ausgegeben:
mkdir: Verzeichnis 'tempdir' kann nicht erstellt werden: Datei existiert
Sie können verwenden test -d
(siehe man test
).
-d file
True, wenn die Datei vorhanden ist und ein Verzeichnis ist.
Zum Beispiel:
test -d "/etc" && echo Exists || echo Does not exist
Hinweis: Der test
Befehl entspricht dem bedingten Ausdruck [
(siehe :) man [
, ist also für Shell-Skripte portierbar.
[
- Dies ist ein Synonym für dastest
Eingebaute, aber das letzte Argument muss wörtlich sein]
, um mit der Eröffnung übereinzustimmen[
.
Weitere Optionen oder weitere Hilfe finden Sie unter:
help [
help test
man test
oder man [
Oder für etwas völlig Nutzloses:
[ -d . ] || echo "No"
Hier ist eine sehr pragmatische Redewendung:
(cd $dir) || return # Is this a directory,
# and do we have access?
Normalerweise verpacke ich es in eine Funktion:
can_use_as_dir() {
(cd ${1:?pathname expected}) || return
}
Oder:
assert_dir_access() {
(cd ${1:?pathname expected}) || exit
}
Das Schöne an diesem Ansatz ist, dass mir keine gute Fehlermeldung einfällt.
cd
Ich erhalte bereits eine einzeilige Standardnachricht zum Standardfehler . Es wird auch mehr Informationen geben, als ich liefern kann. Durch das Ausführen cd
einer Unterschale wirkt ( ... )
sich der Befehl nicht auf das aktuelle Verzeichnis des Aufrufers aus. Wenn das Verzeichnis vorhanden ist, sind diese Unterschale und die Funktion nur ein No-Op.
Als nächstes kommt das Argument, an das wir übergeben cd
: ${1:?pathname expected}
. Dies ist eine ausführlichere Form der Parametersubstitution, die im Folgenden näher erläutert wird.
Tl; dr: Wenn die an diese Funktion übergebene Zeichenfolge leer ist, verlassen wir die Unterschale erneut ( ... )
und kehren mit der angegebenen Fehlermeldung von der Funktion zurück.
Zitat aus der ksh93
Manpage:
${parameter:?word}
Wenn
parameter
gesetzt und nicht null ist, ersetzen Sie seinen Wert. Andernfalls drucken Sieword
die Shell und beenden Sie sie (falls nicht interaktiv). Wenn nicht angegeben,word
wird eine Standardnachricht gedruckt.
und
Wenn der Doppelpunkt
:
in den obigen Ausdrücken weggelassen wird, prüft die Shell nur, ob ein Parameter festgelegt ist oder nicht.
Die Formulierung hier ist der Shell-Dokumentation eigen, da word
sie sich auf jede vernünftige Zeichenfolge beziehen kann, einschließlich Leerzeichen.
In diesem speziellen Fall weiß ich, dass die Standardfehlermeldung 1: parameter not set
nicht ausreicht, daher vergrößere ich den Wertetyp, den wir hier erwarten - den pathname
eines Verzeichnisses.
Eine philosophische Anmerkung:
Die Shell ist keine objektorientierte Sprache, daher heißt es in der Nachricht pathname
nicht directory
. Auf dieser Ebene möchte ich es lieber einfach halten - die Argumente für eine Funktion sind nur Zeichenfolgen.
test -d
wie @Grundlefleck erklärt.
test -d /unreadable/exists
wird fehlschlagen, auch wenn das Argument existiert.
if [ -d "$Directory" -a -w "$Directory" ]
then
#Statements
fi
Der obige Code prüft, ob das Verzeichnis vorhanden und beschreibbar ist.
DIRECTORY=/tmp
if [ -d "$DIRECTORY" ]; then
echo "Exists"
fi
space
nach [
-> [`` -d . Ich habe einen Fehler wegen fehlenden Platzes bekommen
Geben Sie diesen Code an der Bash-Eingabeaufforderung ein:
if [ -d "$DIRECTORY" ]; then
# If true this block of code will execute
fi
find
Überprüfen Sie die Existenz des Ordners in Unterverzeichnissen:
found=`find -type d -name "myDirectory"`
if [ -n "$found"]
then
# The variable 'found' contains the full path where "myDirectory" is.
# It may contain several lines if there are several folders named "myDirectory".
fi
Überprüfen Sie die Existenz eines oder mehrerer Ordner anhand eines Musters im aktuellen Verzeichnis:
found=`find -maxdepth 1 -type d -name "my*"`
if [ -n "$found"]
then
# The variable 'found' contains the full path where folders "my*" have been found.
fi
Beide Kombinationen. Im folgenden Beispiel wird die Existenz des Ordners im aktuellen Verzeichnis überprüft:
found=`find -maxdepth 1 -type d -name "myDirectory"`
if [ -n "$found"]
then
# The variable 'found' is not empty => "myDirectory"` exists.
fi
find -maxdepth 1 -type d -name 'pattern'
. Stört es Sie, wenn ich in Ihrer Antwort diesen Trick anhänge? Prost;)
Eigentlich sollten Sie mehrere Tools verwenden, um einen kugelsicheren Ansatz zu erhalten:
DIR_PATH=`readlink -f "${the_stuff_you_test}"` # Get rid of symlinks and get abs path
if [[ -d "${DIR_PATH}" ]] ; Then # Now you're testing
echo "It's a dir";
fi
Sie müssen sich keine Gedanken über Leerzeichen und Sonderzeichen machen, solange Sie diese verwenden "${}"
.
Beachten Sie, dass dies [[]]
nicht so portabel ist wie []
, aber da die meisten Leute mit modernen Versionen von Bash arbeiten (da die meisten Leute schließlich nicht einmal mit der Befehlszeile arbeiten :-p), ist der Nutzen größer als der Ärger.
Haben Sie darüber nachgedacht, einfach das zu tun, was Sie wollen, if
anstatt zu schauen, bevor Sie springen?
Wenn Sie also vor dem Betreten überprüfen möchten, ob ein Verzeichnis vorhanden ist, versuchen Sie Folgendes:
if pushd /path/you/want/to/enter; then
# Commands you want to run in this directory
popd
fi
Wenn der Pfad, den Sie angeben, pushd
vorhanden ist, geben Sie ihn ein und er wird mit beendet 0
, was bedeutet, dass der then
Teil der Anweisung ausgeführt wird. Wenn es nicht existiert, passiert nichts (außer einer Ausgabe, die besagt, dass das Verzeichnis nicht existiert, was wahrscheinlich sowieso ein hilfreicher Nebeneffekt beim Debuggen ist).
Es scheint besser als das, was erfordert, dass Sie sich wiederholen:
if [ -d /path/you/want/to/enter ]; then
pushd /path/you/want/to/enter
# Commands you want to run in this directory
popd
fi
Dasselbe funktioniert mit cd
, mv
, rm
, etc ... , wenn man sie auf Dateien versuchen, die nicht existieren, werden sie mit einem Fehler beenden und eine Meldung aus sagen , dass es nicht vorhanden ist , und Ihr then
Block wird übersprungen. Wenn Sie sie an vorhandenen Dateien ausprobieren, wird der Befehl ausgeführt und mit dem Status " 0
Beendet", sodass Ihr then
Block ausgeführt werden kann.
Verwenden Sie diesen Code, um mehr als ein Verzeichnis zu überprüfen:
if [ -d "$DIRECTORY1" ] && [ -d "$DIRECTORY2" ] then
# Things to do
fi
Überprüfen Sie, ob das Verzeichnis vorhanden ist, andernfalls erstellen Sie eines:
[ -d "$DIRECTORY" ] || mkdir $DIRECTORY
mkdir -p "$DIRECTORY"
für den gleichen Effekt verwenden.
[[ -d "$DIR" && ! -L "$DIR" ]] && echo "It's a directory and not a symbolic link"
NB: Das Zitieren von Variablen ist eine gute Praxis.
Erläuterung:
-d
: Überprüfen Sie, ob es sich um ein Verzeichnis handelt-L
: Überprüfen Sie, ob es sich um einen symbolischen Link handelt[ -d ~/Desktop/TEMPORAL/ ] && echo "DIRECTORY EXISTS" || echo "DIRECTORY DOES NOT EXIST"
Diese Antwort wurde als Shell-Skript zusammengefasst
$ is_dir ~
YES
$ is_dir /tmp
YES
$ is_dir ~/bin
YES
$ mkdir '/tmp/test me'
$ is_dir '/tmp/test me'
YES
$ is_dir /asdf/asdf
NO
# Example of calling it in another script
DIR=~/mydata
if [ $(is_dir $DIR) == "NO" ]
then
echo "Folder doesnt exist: $DIR";
exit;
fi
function show_help()
{
IT=$(CAT <<EOF
usage: DIR
output: YES or NO, depending on whether or not the directory exists.
)
echo "$IT"
exit
}
if [ "$1" == "help" ]
then
show_help
fi
if [ -z "$1" ]
then
show_help
fi
DIR=$1
if [ -d $DIR ]; then
echo "YES";
exit;
fi
echo "NO";
Mit der -e
Prüfung wird nach Dateien gesucht, einschließlich Verzeichnissen.
if [ -e ${FILE_PATH_AND_NAME} ]
then
echo "The file or directory exists."
fi
Gemäß Jonathans Kommentar:
Wenn Sie das Verzeichnis erstellen möchten und es noch nicht vorhanden ist, verwenden Sie am einfachsten mkdir -p
das Verzeichnis - und alle fehlenden Verzeichnisse im Pfad - und schlagen nicht fehl, wenn das Verzeichnis bereits vorhanden ist, sodass Sie alles tun können sofort mit:
mkdir -p /some/directory/you/want/to/exist || exit 1
if [ -d "$DIRECTORY" ]; then
# Will enter here if $DIRECTORY exists
fi
Das ist nicht ganz richtig ...
Wenn Sie in dieses Verzeichnis wechseln möchten, müssen Sie auch über die Ausführungsrechte für das Verzeichnis verfügen. Möglicherweise müssen Sie auch Schreibrechte haben.
Deshalb:
if [ -d "$DIRECTORY" ] && [ -x "$DIRECTORY" ] ; then
# ... to go to that directory (even if DIRECTORY is a link)
cd $DIRECTORY
pwd
fi
if [ -d "$DIRECTORY" ] && [ -w "$DIRECTORY" ] ; then
# ... to go to that directory and write something there (even if DIRECTORY is a link)
cd $DIRECTORY
touch foobar
fi
Verwenden Sie das file
Programm. Da alle Verzeichnisse auch Dateien unter Linux sind, würde die Ausgabe des folgenden Befehls ausreichen:
file $directory_name
Überprüfen einer nicht vorhandenen Datei: file blah
Ausgabe: cannot open 'blah' (No such file or directory)
Überprüfen eines vorhandenen Verzeichnisses: file bluh
Ausgabe: bluh: directory
Der ls
Befehl in Verbindung mit der -l
Option (lange Auflistung) gibt Attributinformationen zu Dateien und Verzeichnissen zurück.
Insbesondere das erste Zeichen der ls -l
Ausgabe ist normalerweise ein d
oder ein -
(Bindestrich). Im Falle eines ist d
das aufgelistete sicher ein Verzeichnis.
Der folgende Befehl in nur einer Zeile zeigt an, ob die angegebene ISDIR
Variable einen Pfad zu einem Verzeichnis enthält oder nicht:
[[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directory"
Praktische Anwendung:
[claudio@nowhere ~]$ ISDIR="$HOME/Music"
[claudio@nowhere ~]$ ls -ld "$ISDIR"
drwxr-xr-x. 2 claudio claudio 4096 Aug 23 00:02 /home/claudio/Music
[claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directory"
YES, /home/claudio/Music is a directory.
[claudio@nowhere ~]$ touch "empty file.txt"
[claudio@nowhere ~]$ ISDIR="$HOME/empty file.txt"
[claudio@nowhere ~]$ [[ $(ls -ld "$ISDIR" | cut -c1) == 'd' ]] &&
echo "YES, $ISDIR is a directory." ||
echo "Sorry, $ISDIR is not a directoy"
Sorry, /home/claudio/empty file.txt is not a directory
file="foo"
if [[ -e "$file" ]]; then echo "File Exists"; fi;
Wenn Sie überprüfen möchten, ob ein Verzeichnis vorhanden ist, unabhängig davon, ob es sich um ein echtes Verzeichnis oder einen Symlink handelt, verwenden Sie Folgendes:
ls $DIR
if [ $? != 0 ]; then
echo "Directory $DIR already exists!"
exit 1;
fi
echo "Directory $DIR does not exist..."
Erläuterung: Der Befehl "ls" gibt den Fehler "ls: / x: Keine solche Datei oder kein solches Verzeichnis" aus, wenn das Verzeichnis oder der Symlink nicht vorhanden ist, und setzt auch den Rückkehrcode, den Sie über "$?" Abrufen können, auf non -null (normalerweise "1"). Stellen Sie sicher, dass Sie den Rückkehrcode direkt nach dem Aufruf von "ls" überprüfen.
if ! ls $DIR 2>/dev/null; then echo "$DIR does not exist!"; fi
(1)
[ -d Piyush_Drv1 ] && echo ""Exists"" || echo "Not Exists"
(2)
[ `find . -type d -name Piyush_Drv1 -print | wc -l` -eq 1 ] && echo Exists || echo "Not Exists"
(3)
[[ -d run_dir && ! -L run_dir ]] && echo Exists || echo "Not Exists"
Wenn bei einem der oben genannten Ansätze ein Problem festgestellt wird:
Mit dem ls
Befehl; In den Fällen, in denen kein Verzeichnis vorhanden ist, wird eine Fehlermeldung angezeigt
[[ `ls -ld SAMPLE_DIR| grep ^d | wc -l` -eq 1 ]] && echo exists || not exists
-ksh: nicht: nicht gefunden [Keine solche Datei oder kein solches Verzeichnis]
Es gibt großartige Lösungen, aber letztendlich schlägt jedes Skript fehl, wenn Sie sich nicht im richtigen Verzeichnis befinden. Also Code wie folgt:
if [ -d "$LINK_OR_DIR" ]; then
if [ -L "$LINK_OR_DIR" ]; then
# It is a symlink!
# Symbolic link specific commands go here
rm "$LINK_OR_DIR"
else
# It's a directory!
# Directory command goes here
rmdir "$LINK_OR_DIR"
fi
fi
wird nur dann erfolgreich ausgeführt, wenn Sie sich zum Zeitpunkt der Ausführung in einem Verzeichnis befinden, in dem sich ein Unterverzeichnis befindet, nach dem Sie suchen.
Ich verstehe die anfängliche Frage wie folgt: um zu überprüfen, ob ein Verzeichnis existiert, unabhängig von der Position des Benutzers im Dateisystem. Die Verwendung des Befehls 'find' könnte also den Trick machen:
dir=" "
echo "Input directory name to search for:"
read dir
find $HOME -name $dir -type d
Diese Lösung ist gut, da sie die Verwendung von Platzhaltern ermöglicht, eine nützliche Funktion bei der Suche nach Dateien / Verzeichnissen. Das einzige Problem ist, dass, wenn das gesuchte Verzeichnis nicht existiert, der Befehl 'find' nichts in die Standardausgabe druckt (keine elegante Lösung für meinen Geschmack) und dennoch einen Null-Exit hat. Vielleicht könnte jemand dies verbessern.
locate
aber für nichts anderes ...
--
dringend empfohlen (End-of-Options-Marker). Andernfalls schlägt das Skript wie bei Leerzeichen fehl, wenn Ihre Variable etwas enthält, das wie eine Option aussieht.