如果不指定“*”,为什么缓存目录会被删除?

如果不指定“*”,为什么缓存目录会被删除?

我将 ZSH 作为我的默认 shell,并在其之上使用 OhMyZsh。有时我需要删除一些文件并重置一些权限/所有权,所以我使用它的别名。假设我有一个 PHP/Symfony 项目/home/parallels/Development/prj1。有了下面的脚本,我就可以执行它,fixperms prj1但是......

  • 如果我执行该脚本一次并且它删除了内容,$CURRENT_PROJECT/$PROJECT_CACHE我最终会出现以下错误:
fixperms:4: no matches found: /home/parallels/Development/prj1/framework/var/cache/*
  • 如果我删除它*末尾的$CURRENT_PROJECT/$PROJECT_CACHE/*就会删除cache我不想要的文件夹

  • 该文件dev.log永远不会被删除

我在这里缺少什么?

PROJECT=framework
PROJECT_VAR=$PROJECT/var
PROJECT_CACHE=$PROJECT_VAR/cache
PROJECT_LOG=var/log/dev.log

fixperms () {
  if [ -n "$1" ]; then
    CURRENT_PROJECT=$HOME/Development/"$1"

    cd $CURRENT_PROJECT && sudo rm -rf $CURRENT_PROJECT/$PROJECT_CACHE/* && sudo rm -rf $CURRENT_PROJECT/$PROJECT_LOG && sudo chown -R "$(whoami)":root $CURRENT_PROJECT && sudo chmod -R 777 $CURRENT_PROJECT/$PROJECT_VAR
  else
    echo "Missing project param."
  fi
}

注意:我不是 bash/shell 脚本专家,因此我们非常欢迎并提前感谢任何改进

答案1

当您链接所有操作时,&&如果其中一个操作失败,那么该操作就会中断 - 并且该行之后的任何操作都不会被执行。不确定这是有意还是无意。

尝试例如:

echo A && false && echo B
echo A && true && echo B

因此,为什么当项目缓存失败dev.log时永远不会被删除。该行rm之后的任何内容都不会被执行。rm -rf $CURRENT_PROJECT/$PROJECT_CACHE/*

zsh默认情况下关闭nullglob,因此*失败。


无论如何;

您可以先检查目录是否为空,然后再检查rm。更简单的方法是简单地删除它并重新创建它。

setopt nullglob或者可以选择unsetopt nullglob之后。

其他注意事项:

您可能有使用大写变量的原因,但发现最好尽可能避免它。它可能会因环境变量、内置函数等而崩溃。

你应该多引用一些。

我假设$project_log是一个文件,如果是的话-r就没用了。

echo/printf错误到stderr.

project=framework
project_var=$project/var
project_cache=$project_var/cache
project_log=var/log/dev.log

fixperms () {
    if [ -n "$1" ]; then
        current_project="$HOME/Development/$1"

        # Change to project directory. Exit if it fails.
        # The shell should give descriptive error.
        pushd "$current_project" || exit 1

        [ -e "./$project_cache/" ] && sudo rm -r "./$project_cache/"
        sudo mkdir "./$project_cache"

        [ -e "./$project_log" ] && sudo rm "./$project_log"

        sudo chown -R "$(whoami):root" .

        sudo chmod -R 777 "./$project_var"
        # Restore directory we started from
        popd
    else
        printf 'fixperms(): Missing argument: project\n' >&2
    fi
}

您可能想要return 1而不是exit 1全部取决于您如何使用该功能......

无论如何,当我们检查其存在时,将-f其删除。rm

答案2

sudo rm -rf $CURRENT_PROJECT/$PROJECT_CACHE/*

以下是该命令的执行方式(我只提到重要的部分):

  1. shell 扩展最后一个参数中的变量。结果是/home/parallels/Development/prj1/framework/var/cache/*
  2. 最后一个参数包含通配符模式,因此它检查该模式是否与文件匹配。由于您的帐户没有列出 中文件的权限/home/parallels/Development/prj1/framework/var/cache,因此该模式不匹配任何文件(shell 无法区分“我可以确定没有匹配的文件”和“我无法确定是否有任何匹配的文件”)匹配文件”)。不匹配任何文件的通配符模式将被保留。
  3. shellsudo使用参数rm, -rf,执行程序/home/parallels/Development/prj1/framework/var/cache/*
  4. sudorm使用参数-rf,执行/home/parallels/Development/prj1/framework/var/cache/*
  5. rm删除指定的文件,即如果*目录中有一个文件被调用/home/parallels/Development/prj1/framework/var/cache,则该文件被删除(如果*是一个目录,则其内容被递归删除)。

您需要安排具有读取目录权限的 shell 执行通配符扩展(或用于枚举要删除的文件的任何方法)。这意味着通配符扩展必须发生在 sudo 下运行的 shell 中,而不是在调用 sudo 的 shell 中。例如:

sudo sh -c 'rm -rf "$0"/*' "$CURRENT_PROJECT/$PROJECT_CACHE"

请注意扩展事物时所采取的谨慎措施。sudo sh -c 'rm -rf $CURRENT_PROJECT/$PROJECT_CACHE/*'不起作用,因为变量未在内壳中定义(它将运行rm -rf //*,这不是您应该尝试的)。sudo sh -c "rm -rf $CURRENT_PROJECT/$PROJECT_CACHE/*"仅当所涉及的变量值不包含空格等字符时才有效,因为这些值被解释为 shell 代码片段而不是文件名。

注意我不建议运行上面的命令,因为它很脆弱:如果路径不完全符合您的预期,您最终可能会删除系统上的任何内容,并且由于该命令以 root 身份运行,这可能会非常糟糕。相反,您应该仅使用必要的权限运行命令:

sudo -u parallelsowner sh -c 'rm -rf "$0"/*' "$CURRENT_PROJECT/$PROJECT_CACHE"

或者

sudo -g parallelsgroup sh -c 'rm -rf "$0"/*' "$CURRENT_PROJECT/$PROJECT_CACHE"

其中parallelsowner是拥有相关目录及其子目录的用户,或者parallelsgroup是对该目录及其所有子目录具有写访问权限的组。

相关内容