shopt -s extglob 未按预期工作

shopt -s extglob 未按预期工作

我正在尝试递归地更改 WordPress 安装中的文件权限,影响 public_html 文档根文件夹下的所有内容(不包括某些文件夹)。

我已将 extglob 设置为shopt -s extglob

当我运行以下命令时,它无法排除我希望排除的文件夹 ls -R -alh ./public_html/!(*uploads*) | grep uploads

上面列出了上传文件夹中的大量文件——它不应该列出任何文件。

当然上面的命令只是一个测试;我将chmod在实际脚本中使用。

我尝试了许多不同的组合,但都失败了;例如,以下内容:

ls -R -alh ./public_html/!(wp-content/uploads*)

ls: 无法访问 ./public_html/!(wp-content/uploads*): 没有这样的文件或目录

这是我第一次尝试在 shell 命令中使用排除,我可能会犯一个简单的错误。

有什么想法我做错了吗?

请注意:问题的目的是为了更好地理解 extglob 而不是寻找替代方案。我可以编写替代方案,但由于我之前从未使用过 extglob,所以在理解语法时遇到了困难。

答案1

首先,extglob 控制ls在其命令行上看到的内容。确实如此不是控制ls它在命令行上看到的内容的作用。这很重要,因为告诉探索的-R选项lsls递归地它在命令行上看到的任何目录。因此,即使*uploads*没有在命令行上明确给出目录,ls在探索其父目录时也会找到它们。

其次,如你所知,不解析 ls。的输出ls不适用于管道或脚本。试图以这种方式使用它最终会导致不快乐。

第三,要获取所需的文件,请尝试:

find ./public_html ! -path '*uploads*'

解释:

  • 告诉./public_htmlfind 开始在./public_html目录中查找。

  • 就其本身而言,该选项-path '*uploads*'匹配包含模式的任何路径*uploads*。 (与 find 的选项-path类似,但包含目录名称。)但是前面的 表示否定。因此,该选项排除任何匹配的路径。-namepath!! -path '*uploads*'*uploads*

ls要在仍然使用 的功能的同时获得样式输出find,请考虑:

find ./public_html ! -path '*uploads*' -exec ls -dalh {} +

答案2

John1024 为您明显的问题添加了一个很好的解决方案,但根据评论,您想更好地理解 extglob。我怀疑核心误解之一可能是 extglobs 将以递归方式工作——这种说法./public_html/!(*uploads*)会排除名为 的东西./public_html/wp-content/uploads/。 glob(文件名扩展)一次只能在单个目录级别上工作。埋在 bash 手册中,在文件名扩展是:

匹配文件名时,斜杠字符必须始终显式匹配。

因此,正如 John1024 所说,该ls命令没有任何形式的(扩展的)参数./public_html/*uploads*,但它可能有一个参数,例如./public_html/wp-content(与排除的模式不匹配),然后它被-R告知递归列表。

为了*uploads*在命令行中使用 extglobs 排除目录,您必须构建一个具有与子目录一样多的排除项的命令:

ls -dalh ./public_html/!(*uploads*) \
         ./public_html/!(*uploads*)/!(*uploads*) \
         ./public_html/!(*uploads*)/!(*uploads*)/!(*uploads*)
# ... etc ...

...还要小心不要使用 ls 的-R标志。同样的-R风险也适用于 chmod 命令。这里的一个潜在风险是,如果任何子目录有“太多”文件,您将面临风险填充参数列表为了ls。这种方法很脆弱,因为它不会捕获比您编写的模式数量更深的新创建的目录,并且ls如果您曾经有过,它会破坏(会抱怨缺少目录)更少子目录的数量比给定模式的数量多,这是为什么的长解释寻找是适合这项工作的工具。

相关内容