这个问题类似于What is the safest way to empty a directory in *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}/"*

Regex(或sed表达式)应捕获诸如“*”、“/*”、“/**/”、“///*”等路径,但允许诸如“dir”、“dir”、“dir1/dir2/”、“/dir1/dir2/*”等路径。另外,我不知道如何在类似“/dir with space/*”这样的情况下启用shell globbing。有什么想法吗?
编辑:这是我到目前为止想到的:
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不是system或/home目录(在我的例子中,所有这些操作都在/scratch目录下挂载的文件系统上执行)。
注意事项:
测试不太好
不打算与可能包含“..”或“.”的路径一起使用
不应与用户提供的路径一起使用
如果$SOMEPATH中的文件或目录太多(因为命令行长度有限),带星号的rm-rf可能会失败-可以使用“for”循环或“find”命令修复此问题

最佳答案

我发现在bash中使用rm的一个很大的危险是bash通常不会因为错误而停止。这意味着:

cd $SOMEPATH
rm -rf *

如果更改目录失败,则是非常危险的组合。更安全的方法是:
cd $SOMEPATH && rm -rf *

这将确保射频不会运行,除非你真的在$SOMEPATH。这并不能保护你免于一个糟糕的$SOMEPATH,但它可以结合其他人的建议,帮助你的脚本更安全。
编辑:@placeybordeaux很好地指出,如果$SOMEPATH未定义或为空,则cd不会将其视为错误并返回0。鉴于此,除非将SOMPATH作为现有的和非空的第一个验证,否则该答案应被认为是不安全的。我认为没有参数的cd应该是非法命令,因为充其量是执行no-op,更糟的是它可能导致意外行为,但事实就是这样。

09-04 15:16