Wystąp błąd podczas używania pustych zmiennych powłoki

22

Czasami używam, $PROJECT_HOME/*aby usunąć wszystkie pliki w projekcie. Gdy zmienna środowiskowa PROJECT_HOMEnie jest ustawiona (ponieważ tak zrobiłem, sua nowy użytkownik nie ma ustawionej tej zmiennej środowiskowej), rozpoczyna usuwanie wszystkich plików z folderu głównego. To apokaliptyczne.

Jak mogę skonfigurować, bashaby wyświetlał błąd, gdy używam niezdefiniowanej zmiennej środowiskowej w powłoce?

Społeczność
źródło
5
set -uzrobi co chcesz.
cuonglm
czy możesz to zrobić jako odpowiedź?
2
Oczywiście nie zainicjowałbyś swoich warów pustych łańcuchów. [ -z "$VAR" ]działa również z niezainicjowanym VAR. Inicjalizacja miała po prostu pokazać niepożądane zachowanie. Chodzi mi o to, że jeśli wasze zmienne zostaną zainicjowane na puste łańcuchy, w jakikolwiek sposób, i rm -r "$PROJECT_HOME"/*błędnie na tym polegacie set -u, otrzymacie zachowanie „apokaliptyczne”. IHMO, lepiej być bezpiecznym niż żałować, jeśli chodzi o ochronę całej zawartości twojego komputera. set -unie jest bezpieczne.
PSkocik,
3
"To bardzo długo"? Nie powinieneś szukać wygodnego sposobu ręcznego wykonywania niebezpiecznych operacji. Zamiast tego powinieneś utworzyć funkcję, alias lub skrypt, aby robić to, co chcesz; w takim przypadku utworzenie aliasu z sugerowanego polecenia @ PSkocik będzie zarówno bezpieczne, jak i wygodne.
Kyle Strand,
1
Co jeśli użytkownik ustawi PROJECT_HOME=/etc? Samo sprawdzenie pustej wartości nie wystarczy, aby zapobiec kataklizmowi. Nie należy używać zmiennych od niezaufanych użytkowników podczas uruchamiania jako root.
Barmar,

Odpowiedzi:

27

W powłoce POSIX możesz użyć set -u :

#!/bin/sh

set -u
: "${UNSET_VAR}"

lub używając rozszerzenia parametrów :

: "${UNSET_VAR?Unset variable}"

W twoim przypadku powinieneś użyć :?zamiast ?zawieść również na ustawionych, ale pustych zmiennych:

rm -rf -- "${PROJECT_HOME:?PROJECT_HOME empty or unset}"/*
Cuonglm
źródło
17
[ -z "$PROJECT_HOME" ] || rm -r "$PROJECT_HOME"/*

To również złapie przypadek, w którym PROJECT_HOME jest ustawiony, ale niczego nie zawiera.

Przykład:

1) Spowoduje to usunięcie prawie wszystkiego, co można usunąć w systemie (z wyjątkiem plików kropek w środku /(zwykle nie ma żadnych)):

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

2) To nic nie da:

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

Całkowite usunięcie projektu domu i odtworzenie go może być kolejną opcją (jeśli chcesz również pozbyć się plików dotfile):

#no apocalyptic threats in this scenario
rm -r "$PROJECT_HOME"
mkdir "$_" 
PSkocik
źródło
1
-zjest w porządku, ale skoro $PROJECT_HOMEma to być katalog, być może -dbyłoby lepiej. [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME".
kojiro
2
Jeśli PROJECT_HOME jest ustawiony na brak katalogu, jest to błąd niekatastroficzny, prawdopodobnie z powodu literówki. -dCheck by ukryć ten błąd. Myślę, że lepiej będzie, jeśli przejdzie dalej rmi rmnarzeka na to głośno.
PSkocik
2
Jeśli ustawiony jest PROJECT_HOME, ale nazwa nie jest katalogiem, [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME"nic nie zrobi, po cichu. Ale [[ -z $PROJECT_HOME ]] || rm -r "$PROJECT_HOME"po cichu usunie „$ PROJECT_HOME”, nawet jeśli jest to plik, który nie jest katalogiem. Otrzymanie komunikatu o błędzie nigdy nie stanowi problemu:if [[ -d $PROJECT_HOME ]]; then rm -r "$PROJECT_HOME"; else printf '%s is not a directory\n' "$PROJECT_HOME" >&2; fi
kojiro
1
Teraz „przypadkowo” ustaw PROJECT_HOME="/."...
Hagen von Eitzen
1
@HagenvonEitzen Jeśli PROJECT_HOME jest ustawiony na root, procedura opróżniająca PROJECT_HOME opróżni root. Takie jest oczekiwane i całkowicie rozsądne zachowanie. I nawet nie potrzebujesz tej ostatniej kropki.
PSkocik
0

Inny sposób to zrobić:

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

Istnieje wiele podstawień zmiennych, powyższe ma miejsce, gdy „somevar” jest puste (w takim przypadku próbuje się usunąć /tmp/or_this_if_somevar_is_empty/*)

Olivier Dulac
źródło
1
Lub: rm -fr ${ENV_VAR:?suitably caustic message here}/*, ale może być jeszcze warto sprawdzić, że wartość nie mapuje do katalogu głównego, zwracając uwagę, że istnieje wiele sposobów, aby obalić prostych testów: //, /.., /usr/who/../.., ...
Jonathan Leffler
Tak. Jeśli zamierzasz użyć rozszerzenia parametru, równie dobrze możesz użyć tego, który faktycznie generuje błąd
Digital Trauma