web-dev-qa-db-fra.com

Comment quitter un script Shell si le fichier ciblé n'existe pas

Compte tenu du script ci-dessous, je voudrais éviter l'exécution du pipeline si un fichier n'existe pas.

Comment puis-je quitter le script immédiatement si le fichier txt n'est pas trouvé?

ls */*.txt | grep ab1 | awk '{print $1, $1}' | sed "s/\"/\"\"/g" | xargs -L1 mv
22
amine

Vous pouvez vérifier l'existence d'un fichier avec quelque chose comme:

if [[ -f x.txt ]] ; then
    echo file exists.
fi

Pour quitter s'il ne le fait pas quelque chose comme ça suffirait:

if [[ ! -f x.txt ]] ; then
    echo 'File "x.txt" is not there, aborting.'
    exit
fi

Le -f <file> n'est que n parmi les nombreuses expressions conditionnelles que vous pouvez utiliser. Si vous consultez la page de manuel bash sous CONDITIONAL EXPRESSIONS, vous en verrez une multitude.


Si (comme indiqué dans une mise à jour de question) vous souhaitez vérifier si un caractère générique aboutit à des fichiers, vous pouvez simplement le développer, en supprimant les erreurs. S'il n'y en a pas, vous vous retrouverez avec une chaîne vide qui peut être détectée avec -z:

if [[ -z "$(ls -1 */*.txt 2>/dev/null | grep ab1)" ]] ; then
    echo 'There are no "*/*.txt" files.'
    exit
fi

Notez que j'ai utilisé -1 pour forcer un fichier par ligne même si Linux ls le fait par défaut si le périphérique de sortie n'est pas un terminal (à partir de la mémoire). C'est juste au cas où vous essayez ceci sur une machine qui pas force un par ligne dans ce cas.


Gardez cependant à l'esprit que si vous avez des espaces dans vos noms de fichiers, utiliser ls puis awk pour extraire la colonne 1 ne fonctionnera pas trop bien. Par exemple, le fichier abc ab1.txt entraînera l'extraction uniquement du bit abc.

Utilisation de find avec -print0, combiné avec xargs avec -0 est la manière habituelle de traiter correctement les fichiers qui peuvent contenir des caractères "spéciaux". Il existe de nombreuses autres options que vous pouvez donner à find pour vous assurer que seuls les fichiers requis sont traités, tels que -maxdepth pour limiter la distance parcourue dans l'arborescence et -name pour filtrer correctement les noms de fichiers.

Cependant, si vous savez que vous n'aurez jamais ces types de fichiers, il est probablement correct d'utiliser la solution ls, assurez-vous simplement que vous êtes à l'aise avec ses défauts.

40
paxdiablo

Utilisez test

Un moyen rapide et court de tester l'existence:

test -e $FILENAME || exit

Vous pouvez l'enchaîner en faisant:

test -e $FILENAME && something | something-else 

Dans ce cas, something et something-else ne s'exécutera que si le fichier existe.

Par exemple:

➤ test -e ~/.bashrc && echo True || echo False
True
➤ test -e ./exists-not && echo True || echo False
False

Mis à part: Notez que [ est un alias pour test. La sémantique de [[ sont définis par bash et peuvent être trouvés sur la page de manuel bash

Pourtant...

... vous feriez probablement mieux d'utiliser find pour récupérer vos fichiers:

find ./ -maxdepth 2 -name "*ab1*.txt" -exec do-something-to-filename '{}' \;

Comme la sortie de ls ne peut pas être analysée de manière fiable. Cela n'exécutera également que la commande do-something-to-filename si le nom de fichier existe, c'est ce que je pense que vous essayez de faire.

{} sera remplacé par le nom de fichier pour chaque invocation de do-something-to-filename.

9
brice

J'ai essayé ça et ça a marché pour moi

test -s <<your file path>> && exit 0 || <<things to do when file NOT exists>>

Notez que je quitte réellement lorsque le fichier n'est pas présent

0
Kishan B

find ... -exec ... ou find ... -print0 | xargs -0 ... est généralement bien, mais vous pouvez le faire directement avec un glob en utilisant l'option nullglob de bash:

bash-3.2$ echo *foo
*foo
bash-3.2$ shopt -s nullglob
bash-3.2$ echo *foo

bash-3.2$ 

Selon le reste de votre script, vous pouvez ou non vouloir réinitialiser cela avec shopt -u nullglob.

0
Kevin