Emitir un error al usar variables de shell vacías

22

A veces uso, $PROJECT_HOME/*para eliminar todos los archivos del proyecto. Cuando PROJECT_HOMEno se establece la variable de entorno (porque lo hice suy el nuevo usuario no tiene esta variable de entorno establecida), comienza a eliminar todos los archivos de la carpeta raíz. Esto es apocalíptico.

¿Cómo puedo configurar el basherror de lanzamiento cuando uso una variable de entorno indefinida en el shell?

Comunidad
fuente
55
set -uHará lo que quieras.
Cuonglm
¿Puedes hacerlo como la respuesta?
2
Por supuesto, no inicializaría sus vars en cadenas vacías. [ -z "$VAR" ]funciona con un no inicializado VARtambién. La inicialización fue solo para mostrar el comportamiento indeseable. Mi punto es que si alguna vez sus vars se inicializan en cadenas vacías, de cualquier manera, y usted corre rm -r "$PROJECT_HOME"/*confiando erróneamente set -u, obtendrá el comportamiento "apocalíptico". IHMO, es mejor prevenir que curar cuando se trata de proteger todo el contenido de su computadora. set -uno es seguro.
PSkocik
3
"Es muy largo"? No debe buscar una forma conveniente de realizar manualmente operaciones peligrosas. En su lugar, debe crear una función, alias o script para hacer lo que quiera; en este caso, crear un alias del comando sugerido de @ PSkocik será seguro y conveniente.
Kyle Strand
1
¿Qué pasa si el usuario establece PROJECT_HOME=/etc? Simplemente verificar un valor vacío no es suficiente para prevenir el cataclismo. No debe usar variables de usuarios no confiables cuando se ejecuta como root.
Barmar

Respuestas:

27

En el shell POSIX, puede usar set -u :

#!/bin/sh

set -u
: "${UNSET_VAR}"

o usando la expansión de parámetros :

: "${UNSET_VAR?Unset variable}"

En su caso, debe usar en :?lugar de ?fallar también en las variables establecidas pero vacías:

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

Esto también detectará el caso donde PROJECT_HOME se establece pero no contiene nada.

Ejemplo:

1) Esto eliminará prácticamente todo lo que pueda eliminar en su sistema (salvo los archivos de puntos en el interior /(generalmente no hay ninguno)):

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

2) Esto no hará nada:

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

Eliminar completamente su proyecto y volver a crearlo podría ser otra opción (si también desea deshacerse de los archivos de puntos):

#no apocalyptic threats in this scenario
rm -r "$PROJECT_HOME"
mkdir "$_" 
PSkocik
fuente
1
-zestá bien, pero como $PROJECT_HOMEse supone que es un directorio, tal vez -dsería mejor. [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME".
kojiro
2
Si PROJECT_HOME se establece en un no directorio, es un error no catastrófico, posiblemente debido a un error tipográfico. El -dcheque ocultaría ese error. Creo que es mejor si continúa rmy se rmqueja en voz alta.
PSkocik
2
Si PROJECT_HOME está configurado, pero el nombre no es un directorio, [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME"no hará nada, en silencio. Pero [[ -z $PROJECT_HOME ]] || rm -r "$PROJECT_HOME"eliminará silenciosamente "$ PROJECT_HOME", incluso si se trata de un archivo que no es un directorio. Recibir un mensaje de error nunca es un problema:if [[ -d $PROJECT_HOME ]]; then rm -r "$PROJECT_HOME"; else printf '%s is not a directory\n' "$PROJECT_HOME" >&2; fi
kojiro
1
Ahora "accidentalmente" establecido PROJECT_HOME="/."...
Hagen von Eitzen
1
@HagenvonEitzen Si PROJECT_HOME está configurado como root, el procedimiento que vacía PROJECT_HOME vaciará la raíz. Ese es el comportamiento esperado y perfectamente razonable. Y ni siquiera necesitas ese punto final.
PSkocik
0

Otra forma de hacer esto:

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

Hay muchas sustituciones variables, la anterior es cuando "somevar" está vacío (y en ese caso intenta eliminar /tmp/or_this_if_somevar_is_empty/*)

Olivier Dulac
fuente
1
O: rm -fr ${ENV_VAR:?suitably caustic message here}/*, pero podría valer la pena la comprobación de que el valor no se asigna al directorio raíz, observando que hay muchas maneras de subvertir pruebas sencillas: //, /.., /usr/who/../.., ...
Jonathan Leffler
Sí. Si va a usar una expansión de parámetros, también puede usar la que realmente arroja un error
Digital Trauma