3836 Stimmen

Wie kann ich feststellen, ob eine reguläre Datei in der Bash nicht existiert?

Ich habe das folgende Skript verwendet, um zu sehen, ob eine Datei existiert:

#!/bin/bash

FILE=$1     
if [ -f $FILE ]; then
   echo "File $FILE exists."
else
   echo "File $FILE does not exist."
fi

Was ist die richtige Syntax, wenn ich nur prüfen will, ob die Datei no existieren?

#!/bin/bash

FILE=$1     
if [ $FILE does not exist ]; then
   echo "File $FILE does not exist."
fi

226 Stimmen

Ich habe dies gefunden Liste der Bash-Bedingungsanweisungen sehr nützlich.

11 Stimmen

Da ich ein sehr fauler Mensch bin, hätte ich normalerweise die folgende alberne Umgehungskonstruktion verwendet: if [ -f $FILE ]; then; else; echo "File $FILE does not exist."; fi; Wahrscheinlich ist es gut, dass ich stattdessen diese Frage gefunden und gelernt habe, wie man es richtig macht :)

7 Stimmen

Der Einfachheit halber sollten Sie "reguläre Datei" sagen, da die meisten UNIX/POSIX-Dokumente alle Arten von Dateisystemeinträgen einfach als "Dateien" bezeichnen, z. B. ist ein symbolischer Link eine Art von Datei, ebenso wie eine benannte Pipe, eine reguläre Datei, ein Verzeichnis, ein Block-Special, ein Character-Special, ein Socket usw.

81voto

J. M. Becker Punkte 2641

Ich bevorzuge den folgenden Einzeiler, in POSIX Shell-kompatibles Format:

$ [ -f "/$DIR/$FILE" ] || echo "$FILE NOT FOUND"

$ [ -f "/$DIR/$FILE" ] && echo "$FILE FOUND"

Für ein paar Befehle, wie ich es in einem Skript tun würde:

$  [ -f "/$DIR/$FILE" ] || { echo "$FILE NOT FOUND" ; exit 1 ;}

Seitdem ich dies tue, verwende ich nur noch selten die vollständig eingegebene Syntax!

65voto

SD. Punkte 1342

Um das Vorhandensein einer Datei zu prüfen, kann der Parameter eine der folgenden Angaben sein:

-e: Returns true if file exists (regular file, directory, or symlink)
-f: Returns true if file exists and is a regular file
-d: Returns true if file exists and is a directory
-h: Returns true if file exists and is a symlink

Alle nachstehenden Tests gelten für normale Dateien, Verzeichnisse und Symlinks:

-r: Returns true if file exists and is readable
-w: Returns true if file exists and is writable
-x: Returns true if file exists and is executable
-s: Returns true if file exists and has a size > 0

Beispielskript:

#!/bin/bash
FILE=$1

if [ -f "$FILE" ]; then
   echo "File $FILE exists"
else
   echo "File $FILE does not exist"
fi

52voto

Jahid Punkte 19666

Sie können dies tun:

[[ ! -f "$FILE" ]] && echo "File doesn't exist"

oder

if [[ ! -f "$FILE" ]]; then
    echo "File doesn't exist"
fi

Wenn Sie sowohl nach Dateien als auch nach Ordnern suchen wollen, dann verwenden Sie -e anstelle der Option -f . -e liefert true für normale Dateien, Verzeichnisse, Sockets, spezielle Zeichendateien, spezielle Blockdateien usw.

43voto

artdanil Punkte 4524

Sie sollten vorsichtig sein, wenn Sie test für eine nicht quotierte Variable zu verwenden, da dies zu unerwarteten Ergebnissen führen könnte:

$ [ -f ]
$ echo $?
0
$ [ -f "" ]
$ echo $?
1

In der Regel wird empfohlen, die getestete Variable in doppelte Anführungszeichen zu setzen:

#!/bin/sh
FILE=$1

if [ ! -f "$FILE" ]
then
   echo "File $FILE does not exist."
fi

30voto

Stephane Chazelas Punkte 5483

Unter

[ -f "$file" ]

le site [ Befehl führt eine stat() (nicht lstat() ) Systemaufruf auf dem Pfad, der in $file und gibt zurück wahr wenn dieser Systemaufruf erfolgreich ist und der Typ der Datei, wie er von stat() ist " regelmäßig ".

Wenn also [ -f "$file" ] true zurückgibt, können Sie feststellen, dass die Datei tatsächlich existiert und eine reguläre Datei oder ein Symlink ist, der letztendlich zu einer regulären Datei führt (oder zumindest zum Zeitpunkt der stat() ).

Wenn sie jedoch Folgendes zurückgibt falsch (oder wenn [ ! -f "$file" ] o ! [ -f "$file" ] return true), gibt es viele verschiedene Möglichkeiten:

  • die Datei existiert nicht
  • die Datei existiert, ist aber keine regelmäßig Datei (kann ein Gerät, Fifo, Verzeichnis, Socket ... sein)
  • die Datei existiert, aber Sie haben keine Suchberechtigung für das übergeordnete Verzeichnis
  • die Datei existiert, aber der Pfad zum Zugriff auf sie ist zu lang
  • die Datei ist ein Symlink zu einer regulären Datei, aber Sie haben keine Suchberechtigung für einige der Verzeichnisse, die an der Auflösung des Symlinks beteiligt sind.
  • ... einen anderen Grund, warum die stat() Systemaufruf kann fehlschlagen.

Kurz gesagt, so sollte es sein:

if [ -f "$file" ]; then
  printf '"%s" is a path to a regular file or symlink to regular file\n' "$file"
elif [ -e "$file" ]; then
  printf '"%s" exists but is not a regular file\n' "$file"
elif [ -L "$file" ]; then
  printf '"%s" exists, is a symlink but I cannot tell if it eventually resolves to an actual file, regular or not\n' "$file"
else
  printf 'I cannot tell if "%s" exists, let alone whether it is a regular file or not\n' "$file"
fi

Um sicher zu sein, dass die Datei nicht existiert, brauchen wir die stat() Systemaufruf mit einem Fehlercode von ENOENT ( ENOTDIR sagt uns, dass eine der Pfadkomponenten kein Verzeichnis ist (ein weiterer Fall, in dem wir anhand des Pfades feststellen können, dass die Datei nicht existiert). Leider ist die [ Befehl lässt uns das nicht wissen. Er gibt false zurück, unabhängig davon, ob der Fehlercode ENOENT, EACCESS (Zugriff verweigert), ENAMETOOLONG oder ein anderer ist.

Le site [ -e "$file" ] Test kann auch durchgeführt werden mit ls -Ld -- "$file" > /dev/null . In diesem Fall, ls wird Ihnen sagen, warum die stat() fehlgeschlagen, obwohl die Informationen nicht ohne weiteres programmatisch verwendet werden können:

$ file=/var/spool/cron/crontabs/root
$ if [ ! -e "$file" ]; then echo does not exist; fi
does not exist
$ if ! ls -Ld -- "$file" > /dev/null; then echo stat failed; fi
ls: cannot access '/var/spool/cron/crontabs/root': Permission denied
stat failed

Zumindest ls sagt mir, dass es nicht daran liegt, dass die Datei nicht existiert, dass es nicht klappt. Es liegt daran, dass es nicht feststellen kann, ob die Datei existiert oder nicht. Die [ Der Befehl hat das Problem einfach ignoriert.

Mit dem zsh Shell, können Sie den Fehlercode mit dem Befehl $ERRNO spezielle Variable nach der fehlgeschlagenen [ und dekodieren diese Nummer mit dem Befehl $errnos speziellen Array in der zsh/system Modul:

zmodload zsh/system
ERRNO=0
if [ ! -f "$file" ]; then
  err=$ERRNO
  case $errnos[err] in
    ("") echo exists, not a regular file;;
    (ENOENT|ENOTDIR)
       if [ -L "$file" ]; then
         echo broken link
       else
         echo does not exist
       fi;;
    (*) syserror -p "can't tell: " "$err"
  esac
fi

(Vorsicht vor dem $errnos Unterstützung war bei einigen Versionen von zsh wenn sie mit aktuellen Versionen von gcc ).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X