Mengeluarkan kesalahan saat menggunakan variabel shell kosong

22

Terkadang saya menggunakan, $PROJECT_HOME/*untuk menghapus semua file dalam proyek. Ketika variabel lingkungan, PROJECT_HOMEtidak disetel (karena saya lakukan sudan pengguna baru tidak memiliki set variabel lingkungan ini), itu mulai menghapus semua file dari folder root. Ini apokaliptik.

Bagaimana saya bisa mengkonfigurasi bashuntuk melempar kesalahan, ketika saya menggunakan variabel lingkungan yang tidak terdefinisi di shell?

Komunitas
sumber
5
set -uakan melakukan apa yang Anda inginkan.
cuonglm
dapatkah Anda menjadikannya sebagai jawabannya?
2
Tentu saja Anda tidak akan menginisialisasi vars Anda menjadi string kosong. [ -z "$VAR" ]bekerja dengan yang tidak diinisialisasi VARjuga. Inisialisasi itu hanya untuk menunjukkan perilaku yang tidak diinginkan — Maksud saya adalah, jika vars Anda pernah diinisialisasi ke string kosong, dengan cara apa pun, dan Anda menjalankannya dengan rm -r "$PROJECT_HOME"/*mengandalkan kesalahan set -u, Anda akan mendapatkan perilaku "apokaliptik". IHMO, lebih baik aman daripada menyesal ketika harus melindungi seluruh isi komputer Anda. set -utidak aman.
PSkocik
3
"Sangat panjang"? Anda seharusnya tidak mencari cara yang nyaman untuk melakukan operasi berbahaya secara manual. Sebagai gantinya, Anda harus membuat fungsi, alias, atau skrip untuk melakukan apa yang Anda inginkan; dalam hal ini, membuat alias dari perintah yang disarankan @ PSkocik akan aman dan nyaman.
Kyle Strand
1
Bagaimana jika set pengguna PROJECT_HOME=/etc? Hanya memeriksa nilai kosong tidak cukup untuk mencegah bencana. Anda seharusnya tidak menggunakan variabel dari pengguna yang tidak dipercaya saat menjalankan sebagai root.
Barmar

Jawaban:

27

Di shell POSIX, Anda dapat menggunakan set -u :

#!/bin/sh

set -u
: "${UNSET_VAR}"

atau menggunakan Ekspansi Parameter :

: "${UNSET_VAR?Unset variable}"

Dalam kasus Anda, Anda harus menggunakan :?bukan ?juga gagal di set tetapi variabel kosong:

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

Ini juga akan menangkap kasus di mana PROJECT_HOME yang diatur tetapi tidak mengandung apa-apa.

Contoh:

1) Ini akan menghapus hampir semua yang dapat Anda hapus di sistem Anda (kecuali dotfiles di dalamnya /(biasanya tidak ada)):

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

2) Ini tidak akan melakukan apa pun:

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

Benar-benar menghapus rumah proyek Anda dan membuatnya kembali bisa menjadi pilihan lain (jika Anda ingin menyingkirkan dotfiles juga):

#no apocalyptic threats in this scenario
rm -r "$PROJECT_HOME"
mkdir "$_" 
PSkocik
sumber
1
-zok, tapi karena $PROJECT_HOMEseharusnya direktori, mungkin -dakan lebih baik. [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME".
kojiro
2
Jika PROJECT_HOME diatur ke nondirektori, itu adalah kesalahan noncatastrophic, mungkin karena kesalahan ketik. The -dcek akan menyembunyikan kesalahan itu. Saya pikir lebih baik jika terus rmdan rmmengeluh tentang itu keras-keras.
PSkocik
2
Jika PROJECT_HOME disetel, tetapi namanya bukan direktori, maka [[ -d $PROJECT_HOME ]] && rm -r "$PROJECT_HOME"tidak akan melakukan apa-apa, secara diam-diam. Tetapi [[ -z $PROJECT_HOME ]] || rm -r "$PROJECT_HOME"akan secara diam-diam menghapus "$ PROJECT_HOME", meskipun itu file yang bukan direktori. Mendapatkan pesan kesalahan tidak pernah menjadi masalah:if [[ -d $PROJECT_HOME ]]; then rm -r "$PROJECT_HOME"; else printf '%s is not a directory\n' "$PROJECT_HOME" >&2; fi
kojiro
1
Sekarang "tidak sengaja" diatur PROJECT_HOME="/."...
Hagen von Eitzen
1
@HagenvonEitzen Jika PROJECT_HOME disetel ke root, prosedur yang mengosongkan PROJECT_HOME akan mengosongkan root. Itulah perilaku yang diharapkan dan sangat masuk akal. Dan Anda bahkan tidak perlu titik terakhir itu.
PSkocik
0

Cara lain untuk melakukan ini:

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

Ada banyak substitusi variabel, yang di atas adalah ketika "somevar" kosong (dan dalam hal ini mencoba untuk menghapus /tmp/or_this_if_somevar_is_empty/*)

Olivier Dulac
sumber
1
Atau: rm -fr ${ENV_VAR:?suitably caustic message here}/*, tapi mungkin masih layak memeriksa bahwa nilai tidak peta ke direktori root, mencatat bahwa ada banyak cara untuk menumbangkan tes sederhana: //, /.., /usr/who/../.., ...
Jonathan Leffler
Iya nih. Jika Anda akan menggunakan ekspansi parameter, Anda juga dapat menggunakan salah satu yang benar-benar melempar kesalahan
Digital Trauma