Émettre une erreur lors de l'utilisation de variables shell vides

22

Parfois, j'utilise $PROJECT_HOME/*pour supprimer tous les fichiers du projet. Lorsque la variable d'environnement PROJECT_HOMEn'est pas définie (car je l'ai fait suet que le nouvel utilisateur n'a pas cette variable d'environnement définie), elle commence à supprimer tous les fichiers du dossier racine. C'est apocalyptique.

Comment puis-je configurer bashpour générer une erreur, lorsque j'utilise une variable d'environnement non définie dans le shell?

Communauté
la source
5
set -ufera ce que vous voulez.
cuonglm
pouvez-vous en faire la réponse?
2
Bien sûr, vous n'initialiseriez pas vos vars en chaînes vides. [ -z "$VAR" ]fonctionne également avec un fichier non initialisé VAR. L'initialisation était juste pour montrer le comportement indésirable - Mon point est, si jamais vos vars sont initialisés à des chaînes vides, de quelque manière que ce soit, et que vous exécutez à rm -r "$PROJECT_HOME"/*tort en vous appuyant sur set -u, vous obtiendrez le comportement «apocalyptique». IHMO, il vaut mieux prévenir que guérir lorsqu'il s'agit de protéger l'intégralité du contenu de votre ordinateur. set -un'est pas sûr.
PSkocik
3
"Il est très long"? Vous ne devriez pas chercher un moyen pratique d'effectuer manuellement des opérations dangereuses. Au lieu de cela, vous devez créer une fonction, un alias ou un script pour faire ce que vous voulez; dans ce cas, créer un alias à partir de la commande suggérée de @ PSkocik sera à la fois sûr et pratique.
Kyle Strand
1
Et si l'utilisateur définit PROJECT_HOME=/etc? Il ne suffit pas de vérifier une valeur vide pour éviter un cataclysme. Vous ne devez pas utiliser de variables d'utilisateurs non fiables lors de l'exécution en tant que root.
Barmar

Réponses:

27

Dans le shell POSIX, vous pouvez utiliser set -u :

#!/bin/sh

set -u
: "${UNSET_VAR}"

ou en utilisant l' extension des paramètres :

: "${UNSET_VAR?Unset variable}"

Dans votre cas, vous devez utiliser :?au lieu de ?également échouer sur des variables définies mais vides:

rm -rf -- "${PROJECT_HOME:?PROJECT_HOME empty or unset}"/*
cuonglm
la source
17
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/*

Cela interceptera également le cas où PROJECT_HOME est défini mais ne contient rien.

Exemple:

1) Cela supprimera à peu près tout ce que vous pouvez supprimer sur votre système (sauf les fichiers dot à l'intérieur /(il n'y en a généralement pas)):

set -u
PROJECT_HOME=
rm -r "$PROJECT_HOME"/*

2) Cela ne fera rien:

PROJECT_HOME=
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/* 

Supprimer complètement la maison de votre projet et le recréer pourrait être une autre option (si vous souhaitez vous débarrasser des fichiers dot aussi):

#no apocalyptic threats in this scenario
rm -r "$PROJECT_HOME"
mkdir "$_" 
PSkocik
la source
1
-zest ok, mais comme il $PROJECT_HOMEest censé être un répertoire, ce -dserait peut -être mieux. [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME".
kojiro
2
Si PROJECT_HOME est défini sur un non-répertoire, il s'agit d'une erreur non catastrophique, probablement due à une faute de frappe. Le -dchèque cacherait cette erreur. Je pense que c'est mieux si cela continue rmet rms'en plaint à voix haute.
PSkocik
2
Si PROJECT_HOME est défini, mais que le nom n'est pas un répertoire, il [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME"ne fera rien, en silence. Mais [[ -z $PROJECT_HOME ]] || rm -r "$PROJECT_HOME"supprimera silencieusement "$ PROJECT_HOME", même s'il s'agit d'un fichier qui n'est pas un répertoire. Obtenir un message d'erreur n'est jamais un problème:if [[ -d $PROJECT_HOME ]]; then rm -r "$PROJECT_HOME"; else printf '%s is not a directory\n' "$PROJECT_HOME" >&2; fi
kojiro
1
Maintenant "accidentellement" réglé PROJECT_HOME="/."...
Hagen von Eitzen
1
@HagenvonEitzen Si PROJECT_HOME est défini sur root, la procédure qui vide PROJECT_HOME videra root. C'est le comportement attendu et parfaitement raisonnable. Et vous n'avez même pas besoin de ce dernier point.
PSkocik
0

Une autre façon de procéder:

rm -r "${somevar:-/tmp/or_this_if_somevar_is_empty}"/*

Il existe de nombreuses substitutions de variables, celle ci-dessus est lorsque "somevar" est vide (et dans ce cas, il tente de supprimer /tmp/or_this_if_somevar_is_empty/*)

Olivier Dulac
la source
1
Ou: rm -fr ${ENV_VAR:?suitably caustic message here}/*, mais il pourrait encore vérifier la valeur que la valeur ne correspond pas au répertoire racine, faisant remarquer qu'il ya plusieurs façons de subvertir tests simples: //, /.., /usr/who/../.., ...
Jonathan Leffler
Oui. Si vous allez utiliser une extension de paramètre, vous pouvez aussi utiliser celle qui génère une erreur
Digital Trauma