そのため、ホームフォルダ(より正確には書き込み権限を持つすべてのファイル)を削除しました。どうしたの?
build="build"
...
rm -rf "${build}/"*
...
<do other things with $build>
Bashスクリプトで$build
不要になった宣言とすべての目的を削除します。しかし、rm
Bashは喜んでrm -rf /*
それを拡張します。
愚かな気分になってバックアップをインストールし、失われた操作を再開しました。恥ずかしさを避けようとします。
今気になります。そのようなエラーが発生しない、または少なくとも発生する可能性を減らすためにbashスクリプトを書く技術は何ですか?たとえば、私が書いた場合
FileUtils.rm_rf("#{build}/*")
Rubyスクリプトでは、インタプリタがbuild
宣言されていないことについて文句を言うので、言語は私を保護します。
牧場に加えて、私がbashで考慮したものrm
(関連する質問に対する多くの答えで述べたように問題がないわけではありません):
rm -rf "./${build}/"*
これで私の現在の作業(Gitリポジトリ)は破壊されますが、それ以外には何もありません。rm
対応するバリアント/パラメータ化は、現在のディレクトリ外で動作しているときに対話が必要です。 (何も見つかりません。) 同様の効果です。
そうですか?それとも、この意味で「堅牢な」bashスクリプトを書く別の方法はありますか?
ベストアンサー1
set -u
または
set -o nounset
これにより、現在のシェルは設定されていない変数の拡張をエラーとして扱います。
$ unset build
$ set -u
$ rm -rf "$build"/*
bash: build: unbound variable
set -u
そしてset -o nounset
POSIX シェルオプション。
一つ空会う価値があるいいえしかし、エラーが発生します。
これを行うには、次を使用します。
$ rm -rf "${build:?Error, variable is empty or unset}"/*
bash: build: Error, variable is empty or unset
空または設定されていない場合、拡張は${variable:?word}
その値に拡張されます。variable
空であるか設定されていない場合、word
標準エラーに表示され、シェルは拡張をエラーとして扱います(コマンドは実行されず、非対話式シェルで実行すると終了します)。省略すると、:
以下のように設定されていない値に対してのみエラーが発生しますset -u
。
${variable:?word}
はPOSIX パラメータ拡張。
set -e
(またはset -o errexit
)も適用されない限り、これらのいずれも対話型シェルは終了しません。${variable:?word}
変数が空であるか設定されていない場合、スクリプトは終了します。set -u
と一緒に使用すると、スクリプトは終了しますset -e
。
2番目の質問は。rm
現在、ディレクトリ外の作業を制限する方法はありません。
GNUの実装にはマウントされたファイルシステムを再帰的に削除するのを防ぐオプションがありますが、rm
実際には引数をチェックする関数で呼び出しをラップすることなく--one-file-system
できるだけ近づくことができると思います。rm
注:拡張が文字列の一部として発生しない限り、${build}
これはまったく同じです。ここで次の文字は、inなどの変数名の有効な文字です。$build
"${build}x"