Geben Sie einen Fehler aus, wenn Sie leere Shell-Variablen verwenden

22

Manchmal benutze ich, $PROJECT_HOME/*um alle Dateien im Projekt zu löschen. Wenn die Umgebungsvariable PROJECT_HOMEnicht festgelegt ist (da dies suder Fall war und der neue Benutzer diese Umgebungsvariable nicht festgelegt hat), werden alle Dateien aus dem Stammordner gelöscht. Das ist apokalyptisch.

Wie kann ich konfigurieren, bashum Fehler auszulösen, wenn ich eine undefinierte Umgebungsvariable in der Shell verwende?

Gemeinschaft
quelle
5
set -uwerde tun was du willst.
Dienstag,
Schaffst du es als Antwort?
2
Natürlich würden Sie Ihre Vars nicht mit leeren Strings initialisieren. [ -z "$VAR" ]funktioniert auch mit einem nicht initialisierten VAR. Die Initialisierung sollte nur das unerwünschte Verhalten aufzeigen. Mein Punkt ist, wenn Ihre Vars jemals auf irgendeine Weise mit leeren Zeichenfolgen initialisiert werden und Sie rm -r "$PROJECT_HOME"/*versehentlich darauf vertrauen set -u, werden Sie das "apokalyptische" Verhalten erhalten. IHMO, es ist besser, auf Nummer sicher zu gehen, wenn es darum geht, den gesamten Inhalt Ihres Computers zu schützen. set -uist nicht sicher.
PSkocik
3
"Es ist sehr lang"? Sie sollten nicht nach einer bequemen Möglichkeit suchen , gefährliche Vorgänge manuell auszuführen. Stattdessen sollten Sie eine Funktion, einen Alias ​​oder ein Skript erstellen, um das zu tun, was Sie wollen. In diesem Fall ist es sicher und bequem , einen Alias ​​aus dem von @ PSkocik vorgeschlagenen Befehl einzugeben .
Kyle Strand
1
Was ist, wenn der Benutzer einstellt PROJECT_HOME=/etc? Nur nach einem leeren Wert zu suchen, reicht nicht aus, um Katastrophen zu verhindern. Sie sollten keine Variablen von nicht vertrauenswürdigen Benutzern verwenden, wenn Sie als Root ausgeführt werden.
Barmar

Antworten:

27

In der POSIX-Shell können Sie set -u verwenden :

#!/bin/sh

set -u
: "${UNSET_VAR}"

oder mit Parametererweiterung :

: "${UNSET_VAR?Unset variable}"

In Ihrem Fall sollten Sie :?anstelle von ?auch bei gesetzten aber leeren Variablen ausfallen:

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

Dies wird auch den Fall erfassen, PROJECT_HOME in dem gesetzt ist , aber nichts enthält.

Beispiel:

1) Das löscht so ziemlich alles , was Sie können auf Ihrem System löschen (abgesehen von dotfiles innen /(es gibt in der Regel nicht vorhanden)):

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

2) Das macht nichts:

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

Das vollständige Entfernen und Neuerstellen Ihres Projekts zu Hause ist möglicherweise eine weitere Option (wenn Sie auch Punktedateien entfernen möchten):

#no apocalyptic threats in this scenario
rm -r "$PROJECT_HOME"
mkdir "$_" 
PSkocik
quelle
1
-zist ok, aber da $PROJECT_HOMEsoll ein verzeichnis sein, -dwäre vielleicht besser. [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME".
Kojiro
2
Wenn PROJECT_HOME auf ein Nichtverzeichnis gesetzt ist, handelt es sich möglicherweise aufgrund eines Tippfehlers um einen nicht katastrophalen Fehler. Die -dPrüfung würde diesen Fehler verbergen. Ich denke, es ist besser, wenn es weitergeht rmund rmsich laut darüber beschwert.
PSkocik
2
Wenn PROJECT_HOME festgelegt ist, der Name jedoch kein Verzeichnis ist, [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME"wird im Hintergrund nichts unternommen. Aber [[ -z $PROJECT_HOME ]] || rm -r "$PROJECT_HOME"löscht stillschweigend "$ PROJECT_HOME", auch wenn es sich um eine Datei handelt, die kein Verzeichnis ist. Das Erhalten einer Fehlermeldung ist nie ein Problem:if [[ -d $PROJECT_HOME ]]; then rm -r "$PROJECT_HOME"; else printf '%s is not a directory\n' "$PROJECT_HOME" >&2; fi
kojiro
1
Jetzt "versehentlich" einstellen PROJECT_HOME="/."...
Hagen von Eitzen
1
@HagenvonEitzen Wenn PROJECT_HOME auf root gesetzt ist, wird durch die Prozedur, mit der PROJECT_HOME geleert wird, root geleert. Das ist das erwartete und absolut vernünftige Verhalten. Und du brauchst nicht einmal diesen letzten Punkt.
PSkocik
0

Ein anderer Weg dies zu tun:

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

Es gibt viele Variablensubstitutionen. Die obige ist, wenn "somevar" leer ist (und in diesem Fall versucht sie zu löschen /tmp/or_this_if_somevar_is_empty/*).

Olivier Dulac
quelle
1
Oder: rm -fr ${ENV_VAR:?suitably caustic message here}/*, aber es könnte noch wert sein , dass der Wert nicht in das Stammverzeichnis abbildet, unter Hinweis darauf , dass es viele Möglichkeiten , einfache Tests zu unterlaufen: //, /.., /usr/who/../.., ...
Jonathan Leffler
Ja. Wenn Sie eine Parametererweiterung verwenden, können Sie auch diejenige verwenden, die tatsächlich einen Fehler auslöst
Digital Trauma