8

この質問は、* nix でディレクトリを空にする最も安全な方法は何ですか? に似ています。

いくつかのパス定数を定義し、それらをファイルとディレクトリの操作 (コピー、名前変更、削除) に使用する bash スクリプトを作成しています。多くの場合、次のようなことを行う必要があります。

rm -rf "/${PATH1}"
rm -rf "${PATH2}/"*

このスクリプトを開発している間、PATH1 や PATH2 などの名前の入力ミスを防ぎ、それらが空の文字列に展開されてディスク全体が消去される状況を回避したいと考えています。特別なラッパーを作成することにしました:

rmrf() {
    if [[ $1 =~ "regex" ]]; then
        echo "Ignoring possibly unsafe path ${1}"
        exit 1
    fi

    shopt -s dotglob
    rm -rf -- $1
    shopt -u dotglob
}

次のように呼び出されます。

rmrf "/${PATH1}"
rmrf "${PATH2}/"*

正規表現 (または sed 式) は、「*」、「/*」、「/**/」、「///*」などのパスをキャッチする必要がありますが、「dir」、「/dir」、「/dir1」などのパスは許可します。 /dir2/"、"/dir1/dir2/*". また、「/dir with space/*」のような場合にシェルのグロブを有効にする方法もわかりません。何か案は?

編集:これは私がこれまでに思いついたものです:

rmrf() {
    local RES
    local RMPATH="${1}"
    SAFE=$(echo "${RMPATH}" | sed -r 's:^((\.?\*+/+)+.*|(/+\.?\*+)+.*|[\.\*/]+|.*/\.\*+)$::g')
    if [ -z "${SAFE}" ]; then
        echo "ERROR! Unsafe deletion of ${RMPATH}"
        return 1
    fi

    shopt -s dotglob
    if [ '*' == "${RMPATH: -1}" ]; then
        echo rm -rf -- "${RMPATH/%\*/}"*
        RES=$?
    else
        echo rm -rf -- "${RMPATH}"
        RES=$?
    fi
    shopt -u dotglob

    return $RES
}

使用目的は次のとおりです (引用符内のアスタリスクに注意してください):

rmrf "${SOMEPATH}"
rmrf "${SOMEPATH}/*"

$SOMEPATH はシステムまたは /home ディレクトリではありません (私の場合、そのような操作はすべて /scratch ディレクトリの下にマウントされたファイルシステムで実行されます)。

警告:

  • あまりよくテストされていません
  • 「..」または「.」を含む可能性のあるパスでの使用は意図されていません。
  • ユーザー指定のパスでは使用しないでください
  • $SOMEPATH 内にファイルまたはディレクトリが多すぎる場合、アスタリスク付きの rm -rf はおそらく失敗する可能性があります (コマンド ラインの長さが限られているため)。これは、'for' ループまたは 'find' コマンドで修正できます。
4

10 に答える 10

10

私はbashのrmに大きな危険があることを発見しました。それは、bashが通常エラーのために停止しないことです。つまり、次のことを意味します。

cd $SOMEPATH
rm -rf *

ディレクトリの変更に失敗した場合、これは非常に危険な組み合わせです。より安全な方法は次のとおりです。

cd $SOMEPATH && rm -rf *

これにより、実際に$ SOMEPATHにいない限り、rfが実行されなくなります。これは悪い$SOMEPATHからあなたを保護するものではありませんが、スクリプトをより安全にするために他の人からのアドバイスと組み合わせることができます。

編集:@placeybordeauxは、$ SOMEPATHが未定義または空の場合cd、エラーとして扱われず、0を返すという良い点を示しています。これに照らして、$ SOMEPATHが最初に存在し、空でないことが検証されない限り、この回答は安全でないと見なされます。 。引数cdがない場合は、せいぜい何も実行せず、最悪の場合は予期しない動作につながる可能性があるため、違法なコマンドである必要があると思いますが、それは実際のことです。

于 2009-06-14T13:45:53.150 に答える
5

set -u初期化されていない変数を使用すると、終了するbash ディレクティブがあります。例として、ここでそれについて読みました。rm -rfそれがあなたが探しているものだと思います。そしてこちらがセットの説明書

于 2009-07-23T02:37:48.197 に答える
2

あなたは使用することができます

set -f    # cf. help set 

ファイル名の生成を無効にするには (*)。

于 2009-06-15T06:34:00.787 に答える
2

「rm」コマンドには、「/」の削除を回避するためのパラメーターがあると思います。見てみな。

于 2009-06-14T12:38:56.523 に答える
2

コマンド引数を直接使用するのではなく、realpath(1) を使用することをお勧めします。これにより、/A/B/../ やシンボリック リンクなどを回避できます。

于 2009-06-14T12:42:29.840 に答える
2

通常、「 」などの操作を含むコマンドを開発する場合は、rm -fr開発中に削除を無効にします。それを行う1つの方法は次のとおりです。

RMRF="echo rm -rf"
...
$RMRF "/${PATH1}"

これは、何を削除する必要があるかを示していますが、削除しません。開発中に手動でクリーンアップを行います - すべてを台無しにするリスクを回避するために支払うのは小さな代償です。

' ' という表記"/${PATH1}"は少し変わっています。通常は、PATH1 に絶対パス名が含まれていることを確認します。

' ' でメタ文字を使用する"${PATH2}/"*のは賢明ではなく、不必要です。これを使用する場合と ' ' のみを使用する場合の唯一の違いは"${PATH2}"、PATH2 で指定されたディレクトリにドットで始まる名前のファイルまたはディレクトリが含まれている場合、それらのファイルまたはディレクトリは削除されないことです。そのような設計はありそうもなく、かなり壊れやすいです。PATH2 を渡すだけで、再帰的な削除にその仕事をさせる方がはるかに簡単です。末尾にスラッシュを追加することは、必ずしも悪い考えではありません。システムは$PATH2、ファイル名だけでなくディレクトリ名が含まれていることを確認する必要がありますが、追加の保護はかなり最小限です。

' ' でグロビングを使用rm -frすることは、通常は悪い考えです。事故を防ぐために、正確で制限的であり、それが行うことを制限したいと考えています。もちろん、開発中のコマンド (開発中のシェル スクリプト) を root として実行することは決してありません。これは自殺行為です。または、root 権限が絶対に必要な場合は、完全に安全であると確信できるまで、削除操作を無力化します。

于 2009-06-14T12:47:51.743 に答える
1

可能であれば、' ' など、ファイル システムの他の場所には見られないような、ハードコードされた名前のフォルダーにすべてを入れてみてくださいfoofolderrmrf()次に、関数を次のように記述できます。

rmrf() {
    rm -rf "foofolder/$PATH1"
    # or
    rm -rf "$PATH1/foofolder"
}

その関数が必要なファイル以外を削除できる方法はありません。

于 2009-06-15T01:55:47.250 に答える
1

正規表現を使用する必要はありません。
保護したいディレクトリを変数に割り当ててから、変数を反復処理するだけです。例えば:

protected_dirs="/ /bin /usr/bin /home $HOME"
$protected_dirs の d の場合。行う
    if [ "$1" = "$d" ]; それから
        RM=0
        壊す;
    フィ
終わり
[ ${rm:-1} -eq 1 ]; それから
    rm -rf $1
フィ
于 2009-10-28T19:56:02.413 に答える