Comment vérifier si un fichier existe dans un script shell

176

J'aimerais écrire un script shell qui vérifie si un certain fichier archived_sensor_data.jsonexiste et, si oui, le supprime. Après http://www.cyberciti.biz/tips/find-out-if-file-exists-with-conditional-expressions.html , j'ai essayé ce qui suit:

[-e archived_sensor_data.json] && rm archived_sensor_data.json

Cependant, cela génère une erreur

[-e: command not found

lorsque j'essaye d'exécuter le test_controllerscript résultant en utilisant la ./test_controllercommande. Quel est le problème avec le code?

Kurt Peek
la source
2
Vous devez définir un ou plusieurs espaces entre le crochet ouvrant "[" et l'option "-e" comme entre le nom de fichier et le crochet fermant "]"
Konstantin Yaniv

Réponses:

351

Il vous manque un espace requis entre le crochet et -e:

#!/bin/bash
if [ -e x.txt ]
then
    echo "ok"
else
    echo "nok"
fi
chris01
la source
12
J'ai finalement ajouté deux espaces vides, l' un après l'ouverture carrée et un support avant celui de clôture: [ -e archived_sensor_data.json ] && rm archived_sensor_data.json. Le script semble fonctionner maintenant.
Kurt Peek
3
Cela fonctionne également en utilisant if [ -e "$1" ](argument d'entrée de nom de fichier).
Edward
2
La principale différence ici est le fait que vous utilisez le script "bash" au lieu du script "shell". Notez que la première ligne que vous avez ajoutée était #! / Bin / bash, donc vous dites à la machine d'utiliser "bash" au lieu de sh. Parce que sh ne reconnaît pas cet argument "-e"
Nick Cuevas
29

Voici une méthode alternative utilisant ls:

(ls x.txt && echo yes) || echo no

Si vous souhaitez masquer une sortie de lspour ne voir que oui ou non, redirigez stdoutet stderrvers /dev/null:

(ls x.txt >> /dev/null 2>&1 && echo yes) || echo no
Philip Kirkbride
la source
1
Ce code signifie: "s'il lsréussit, il existe un tel fichier, sinon il n'y en a pas". En cas d' lséchec, cela ne signifie pas que le fichier est manquant. Cela pourrait être une autre erreur. Par exemple, créez un fichier dans le répertoire appartenant à root et essayez de le faire lssous un utilisateur normal. Il échouera avec Permission denied, ce qui n'est pas équivalent à ce que le fichier n'existe pas.
Tigran
9

La toile de fond de ma recommandation de solution est l'histoire d'un ami qui, bien dans la deuxième semaine de son premier travail, a nettoyé la moitié d'un serveur de construction. Donc, la tâche de base est de déterminer si un fichier existe, et si c'est le cas, supprimons-le. Mais il y a quelques rapides perfides sur cette rivière:

  • Tout est un fichier.

  • Les scripts n'ont un réel pouvoir que s'ils résolvent des tâches générales

  • Pour être général, nous utilisons des variables

  • Nous utilisons souvent -f force dans les scripts pour éviter une intervention manuelle

  • Et aussi aimer -r récursif pour nous assurer que nous créons, copions et détruisons en temps opportun.

Considérez le scénario suivant:

Nous avons le fichier que nous voulons supprimer: filesexists.json

Ce nom de fichier est stocké dans une variable

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

Nous avons également une variable de chemin pour rendre les choses vraiment flexibles

<host>:~/Documents/thisfolderexists pathtofile=".."

<host>:~/Documents/thisfolderexists ls $pathtofile

filesexists.json  history20170728  SE-Data-API.pem  thisfolderexists

Voyons donc si -efait ce qu'il est censé faire. Les fichiers existent-ils?

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

Cela fait. La magie.

Cependant, que se passerait-il si la variable de fichier était accidentellement évaluée à nuffin '

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists [ -e $pathtofile/$filevariable ]; echo $?

0

Quoi? Il est censé revenir avec une erreur ... Et c'est le début de l'histoire comment tout ce dossier a été supprimé par accident

Une alternative pourrait être de tester spécifiquement ce que nous considérons comme un `` fichier ''

<host>:~/Documents/thisfolderexists filevariable="filesexists.json"

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

0

Donc le fichier existe ...

<host>:~/Documents/thisfolderexists filevariable=""

<host>:~/Documents/thisfolderexists test -f $pathtofile/$filevariable; echo $?

1

Donc, ce n'est pas un fichier et peut-être, nous ne voulons pas supprimer tout ce répertoire

man test a ce qui suit à dire:

-b FILE

       FILE exists and is block special

-c FILE

       FILE exists and is character special

-d FILE

       FILE exists and is a directory

-e FILE

       FILE exists

-f FILE

       FILE exists and is a regular file

...

-h FILE

       FILE exists and is a symbolic link (same as -L)
Lefty G Balogh
la source
4

En interne, la commande rm doit de toute façon tester l'existence du fichier,
alors pourquoi ajouter un autre test? Juste question

rm filename

et il disparaîtra après cela, que ce soit là ou non.
Utilisez rm -f si vous ne voulez pas de messages sur des fichiers inexistants.

Si vous devez prendre des mesures si le fichier n'existe PAS, vous devez le tester vous-même. D'après votre exemple de code, ce n'est pas le cas dans cette instance.

TG
la source
1
C'est en fait une réponse tout à fait valable pour la commande rm. Pour les autres commandes, je suggère plutôt de tester avec -e.
warhansen
Sauf que ce n'est pas ce que pose la question.
Crayons
1
C'est vraiment ce que demande la question, si vous lisez toute la question, y compris la partie "... et (si oui) ... la supprime".
TG
1

Si vous utilisez un NFS, "test" est une meilleure solution, car vous pouvez lui ajouter un délai d'attente, au cas où votre NFS serait en panne:

time timeout 3 test -f 
/nfs/my_nfs_is_currently_down
real    0m3.004s <<== timeout is taken into account
user    0m0.001s
sys     0m0.004s
echo $?
124   <= 124 means the timeout has been reached

Une construction "[-e mon_fichier]" se fige jusqu'à ce que le NFS soit à nouveau fonctionnel:

if [ -e /nfs/my_nfs_is_currently_down ]; then echo "ok" else echo "ko" ; fi

<no answer from the system, my session is "frozen">
FCA69
la source
testet [sont synonymes. Vous pouvez également utiliser timeoutavec [, et testse fige également si NFS se bloque.
cet autre gars le