Comment savoir si un fichier ordinaire n'existe pas dans Bash?


Answers

Test de fichier Bash

-b filename - Bloquer le fichier spécial
-c filename - Fichier de caractères spéciaux
-d directoryname - Vérifie l'existence du répertoire
-e filename - Vérifie l'existence du fichier, quel que soit le type (noeud, répertoire, socket, etc.)
-f filename - Vérifie si l'existence d'un fichier n'est pas un répertoire
-G filename - Vérifie si le fichier existe et s'il appartient à un ID de groupe efficace
-G filename set-group-id - Vrai si le fichier existe et que set-group-id
-k filename - bit collant
-L filename - Lien symbolique
-O filename - Vrai si le fichier existe et appartient à l'ID utilisateur effectif
-r filename - Vérifie si le fichier est lisible
-S filename - Vérifie si le fichier est socket
-s filename - Vérifie si le fichier est de taille différente de zéro
-u filename - Vérifie si le bit set-user-id du fichier est positionné
-w filename - Vérifie si le fichier est accessible en écriture
-x filename - Vérifie si le fichier est exécutable

Comment utiliser:

#!/bin/bash
file=./file
if [ -e "$file" ]; then
    echo "File exists"
else 
    echo "File does not exist"
fi 

Une expression de test peut être annulée en utilisant le ! opérateur

#!/bin/bash
file=./file
if [ ! -e "$file" ]; then
    echo "File does not exist"
else 
    echo "File exists"
fi 
Question

J'ai utilisé le script suivant pour voir si un fichier existe:

#!/bin/bash

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

Quelle est la syntaxe correcte à utiliser si je veux seulement vérifier si le fichier n'existe pas ?

#!/bin/bash

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



Dans

[ -f "$file" ]

la commande [ fait un appel système stat() (pas lstat() ) sur le chemin stocké dans $file et renvoie la valeur true si cet appel système réussit et le type du fichier retourné par stat() est "regular".

Donc, si [ -f "$file" ] renvoie true, vous pouvez dire que le fichier existe et qu'il s'agit d'un fichier normal ou d'un lien symbolique résolvant un fichier normal (ou du moins c'était au moment de stat() ).

Cependant, si elle renvoie false (ou si [ ! -f "$file" ] ou ! [ -f "$file" ] renvoie true), il existe plusieurs possibilités:

  • le fichier n'existe pas
  • le fichier existe mais n'est pas un fichier normal
  • le fichier existe mais vous n'avez pas d'autorisation de recherche sur le répertoire parent
  • le fichier existe mais ce chemin d'accès est trop long
  • le fichier est un lien symbolique vers un fichier normal, mais vous n'avez pas l'autorisation de recherche sur certains des répertoires impliqués dans la résolution du lien symbolique.
  • ... toute autre raison pour laquelle l'appel système stat() peut échouer.

En bref, il devrait être:

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

Pour être sûr que le fichier n'existe pas, nous aurions besoin de l'appel système stat() pour retourner avec un code d'erreur ENOENT ( ENOTDIR nous dit que l'un des composants du path n'est pas un répertoire, c'est un autre cas où nous pouvons le dire le fichier n'existe pas par ce chemin). Malheureusement, la commande ne nous le dit pas. Il retournera faux si le code d'erreur est ENOENT, EACCESS (permission refusée), ENAMETOOLONG ou n'importe quoi d'autre.

Le test [ -e "$file" ] peut aussi être fait avec ls -Ld -- "$file" > /dev/null . Dans ce cas, ls vous dira pourquoi la fonction stat() échoué, bien que l'information ne puisse pas être utilisée facilement par programmation:

$ 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

Au moins, ls me dit que ce n'est pas parce que le fichier n'existe pas qu'il échoue. C'est parce qu'il ne peut pas dire si le fichier existe ou non. La commande [ simplement ignoré le problème.

Avec le shell zsh , vous pouvez interroger le code d'erreur avec la variable spéciale $ERRNO après la commande $ERRNO [ et décoder ce nombre en utilisant le tableau spécial $errnos dans le module zsh/system :

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;;
    (*) echo "can't tell"; syserror "$err"
  esac
fi

(attention, le support de $errnos est cassé avec certaines versions de zsh lorsqu'il est construit avec les versions récentes de gcc ).




Vous devez faire attention à l'exécution d'un test pour une variable sans guillemets, car cela peut produire des résultats inattendus:

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

La recommandation est généralement d'avoir la variable testée entourée de guillemets doubles:

#!/bin/sh
FILE=$1

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



Pour inverser un test, utilisez "!". Cela équivaut à l'opérateur logique "not" dans d'autres langues. Essaye ça:

if [ ! -f /tmp/foo.txt ];
then
    echo "File not found!"
fi

Ou écrit d'une manière légèrement différente:

if [ ! -f /tmp/foo.txt ]
    then echo "File not found!"
fi

Ou vous pouvez utiliser:

if ! [ -f /tmp/foo.txt ]
    then echo "File not found!"
fi

Ou, en présageant tous ensemble:

if ! [ -f /tmp/foo.txt ]; then echo "File not found!"; fi

Qui peut être écrit (en utilisant alors "et" operator: &&) comme:

[ ! -f /tmp/foo.txt ] && echo "File not found!"

Ce qui semble plus court comme ceci:

[ -f /tmp/foo.txt ] || echo "File not found!"



Je préfère faire le one-liner suivant, au format compatible shell POSIX :

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

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

Pour quelques commandes, comme je le ferais dans un script:

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

Une fois que j'ai commencé à faire cela, j'utilise rarement la syntaxe entièrement typée !!




Ce script shell fonctionne également pour trouver un fichier dans un répertoire:

echo "enter file"

read -r a

if [ -s /home/trainee02/"$a" ]
then
    echo "yes. file is there."
else
    echo "sorry. file is not there."
fi



Ce code fonctionne également.

#!/bin/bash
FILE=$1
if [ -f $FILE ]; then
 echo "File '$FILE' Exists"
else
 echo "The File '$FILE' Does Not Exist"
fi



[[ -f $FILE ]] || printf '%s does not exist!\n' "$FILE"

En outre, il est possible que le fichier soit un lien symbolique brisé, ou un fichier non-régulier, comme par exemple une socket, un périphérique ou un fifo. Par exemple, pour ajouter une vérification des liens symboliques rompus:

if [[ ! -f $FILE ]]; then
    if [[ -L $FILE ]]; then
        printf '%s is a broken symlink!\n' "$FILE"
    else
        printf '%s does not exist!\n' "$FILE"
    fi
fi



Links